1 //===-- include/flang/Semantics/type.h --------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef FORTRAN_SEMANTICS_TYPE_H_
10 #define FORTRAN_SEMANTICS_TYPE_H_
11 
12 #include "flang/Common/Fortran.h"
13 #include "flang/Common/idioms.h"
14 #include "flang/Evaluate/expression.h"
15 #include "flang/Parser/char-block.h"
16 #include <algorithm>
17 #include <iosfwd>
18 #include <map>
19 #include <optional>
20 #include <string>
21 #include <variant>
22 #include <vector>
23 
24 namespace llvm {
25 class raw_ostream;
26 }
27 
28 namespace Fortran::parser {
29 struct Keyword;
30 }
31 
32 namespace Fortran::semantics {
33 
34 class Scope;
35 class SemanticsContext;
36 class Symbol;
37 
38 /// A SourceName is a name in the cooked character stream,
39 /// i.e. a range of lower-case characters with provenance.
40 using SourceName = parser::CharBlock;
41 using TypeCategory = common::TypeCategory;
42 using SomeExpr = evaluate::Expr<evaluate::SomeType>;
43 using MaybeExpr = std::optional<SomeExpr>;
44 using SomeIntExpr = evaluate::Expr<evaluate::SomeInteger>;
45 using MaybeIntExpr = std::optional<SomeIntExpr>;
46 using SubscriptIntExpr = evaluate::Expr<evaluate::SubscriptInteger>;
47 using MaybeSubscriptIntExpr = std::optional<SubscriptIntExpr>;
48 using KindExpr = SubscriptIntExpr;
49 
50 // An array spec bound: an explicit integer expression, assumed size
51 // or implied shape(*), or assumed or deferred shape(:).  In the absence
52 // of explicit lower bounds it is not possible to distinguish assumed
53 // shape bounds from deferred shape bounds without knowing whether the
54 // particular symbol is an allocatable/pointer or a non-allocatable
55 // non-pointer dummy; use the symbol-based predicates for those
56 // determinations.
57 class Bound {
58 public:
Star()59   static Bound Star() { return Bound(Category::Star); }
Colon()60   static Bound Colon() { return Bound(Category::Colon); }
Bound(MaybeSubscriptIntExpr && expr)61   explicit Bound(MaybeSubscriptIntExpr &&expr) : expr_{std::move(expr)} {}
62   explicit Bound(common::ConstantSubscript bound);
63   Bound(const Bound &) = default;
64   Bound(Bound &&) = default;
65   Bound &operator=(const Bound &) = default;
66   Bound &operator=(Bound &&) = default;
isExplicit()67   bool isExplicit() const { return category_ == Category::Explicit; }
isStar()68   bool isStar() const { return category_ == Category::Star; }
isColon()69   bool isColon() const { return category_ == Category::Colon; }
GetExplicit()70   MaybeSubscriptIntExpr &GetExplicit() { return expr_; }
GetExplicit()71   const MaybeSubscriptIntExpr &GetExplicit() const { return expr_; }
SetExplicit(MaybeSubscriptIntExpr && expr)72   void SetExplicit(MaybeSubscriptIntExpr &&expr) {
73     CHECK(isExplicit());
74     expr_ = std::move(expr);
75   }
76 
77 private:
78   enum class Category { Explicit, Star, Colon };
Bound(Category category)79   Bound(Category category) : category_{category} {}
Bound(Category category,MaybeSubscriptIntExpr && expr)80   Bound(Category category, MaybeSubscriptIntExpr &&expr)
81       : category_{category}, expr_{std::move(expr)} {}
82   Category category_{Category::Explicit};
83   MaybeSubscriptIntExpr expr_;
84   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Bound &);
85 };
86 
87 // A type parameter value: integer expression, assumed/implied(*),
88 // or deferred(:).
89 class ParamValue {
90 public:
Assumed(common::TypeParamAttr attr)91   static ParamValue Assumed(common::TypeParamAttr attr) {
92     return ParamValue{Category::Assumed, attr};
93   }
Deferred(common::TypeParamAttr attr)94   static ParamValue Deferred(common::TypeParamAttr attr) {
95     return ParamValue{Category::Deferred, attr};
96   }
97   ParamValue(const ParamValue &) = default;
98   explicit ParamValue(MaybeIntExpr &&, common::TypeParamAttr);
99   explicit ParamValue(SomeIntExpr &&, common::TypeParamAttr attr);
100   explicit ParamValue(common::ConstantSubscript, common::TypeParamAttr attr);
isExplicit()101   bool isExplicit() const { return category_ == Category::Explicit; }
isAssumed()102   bool isAssumed() const { return category_ == Category::Assumed; }
isDeferred()103   bool isDeferred() const { return category_ == Category::Deferred; }
GetExplicit()104   const MaybeIntExpr &GetExplicit() const { return expr_; }
105   void SetExplicit(SomeIntExpr &&);
isKind()106   bool isKind() const { return attr_ == common::TypeParamAttr::Kind; }
isLen()107   bool isLen() const { return attr_ == common::TypeParamAttr::Len; }
set_attr(common::TypeParamAttr attr)108   void set_attr(common::TypeParamAttr attr) { attr_ = attr; }
109   bool operator==(const ParamValue &that) const {
110     return category_ == that.category_ && expr_ == that.expr_;
111   }
112   bool operator!=(const ParamValue &that) const { return !(*this == that); }
113   std::string AsFortran() const;
114 
115 private:
116   enum class Category { Explicit, Deferred, Assumed };
ParamValue(Category category,common::TypeParamAttr attr)117   ParamValue(Category category, common::TypeParamAttr attr)
118       : category_{category}, attr_{attr} {}
119   Category category_{Category::Explicit};
120   common::TypeParamAttr attr_{common::TypeParamAttr::Kind};
121   MaybeIntExpr expr_;
122   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ParamValue &);
123 };
124 
125 class IntrinsicTypeSpec {
126 public:
category()127   TypeCategory category() const { return category_; }
kind()128   const KindExpr &kind() const { return kind_; }
129   bool operator==(const IntrinsicTypeSpec &x) const {
130     return category_ == x.category_ && kind_ == x.kind_;
131   }
132   bool operator!=(const IntrinsicTypeSpec &x) const { return !operator==(x); }
133   std::string AsFortran() const;
134 
135 protected:
136   IntrinsicTypeSpec(TypeCategory, KindExpr &&);
137 
138 private:
139   TypeCategory category_;
140   KindExpr kind_;
141   friend llvm::raw_ostream &operator<<(
142       llvm::raw_ostream &os, const IntrinsicTypeSpec &x);
143 };
144 
145 class NumericTypeSpec : public IntrinsicTypeSpec {
146 public:
NumericTypeSpec(TypeCategory category,KindExpr && kind)147   NumericTypeSpec(TypeCategory category, KindExpr &&kind)
148       : IntrinsicTypeSpec(category, std::move(kind)) {
149     CHECK(common::IsNumericTypeCategory(category));
150   }
151 };
152 
153 class LogicalTypeSpec : public IntrinsicTypeSpec {
154 public:
LogicalTypeSpec(KindExpr && kind)155   explicit LogicalTypeSpec(KindExpr &&kind)
156       : IntrinsicTypeSpec(TypeCategory::Logical, std::move(kind)) {}
157 };
158 
159 class CharacterTypeSpec : public IntrinsicTypeSpec {
160 public:
CharacterTypeSpec(ParamValue && length,KindExpr && kind)161   CharacterTypeSpec(ParamValue &&length, KindExpr &&kind)
162       : IntrinsicTypeSpec(TypeCategory::Character, std::move(kind)),
163         length_{std::move(length)} {}
length()164   const ParamValue &length() const { return length_; }
165   bool operator==(const CharacterTypeSpec &that) const {
166     return kind() == that.kind() && length_ == that.length_;
167   }
168   std::string AsFortran() const;
169 
170 private:
171   ParamValue length_;
172   friend llvm::raw_ostream &operator<<(
173       llvm::raw_ostream &os, const CharacterTypeSpec &x);
174 };
175 
176 class ShapeSpec {
177 public:
178   // lb:ub
MakeExplicit(Bound && lb,Bound && ub)179   static ShapeSpec MakeExplicit(Bound &&lb, Bound &&ub) {
180     return ShapeSpec(std::move(lb), std::move(ub));
181   }
182   // 1:ub
MakeExplicit(Bound && ub)183   static const ShapeSpec MakeExplicit(Bound &&ub) {
184     return MakeExplicit(Bound{1}, std::move(ub));
185   }
186   // 1:
MakeAssumedShape()187   static ShapeSpec MakeAssumedShape() {
188     return ShapeSpec(Bound{1}, Bound::Colon());
189   }
190   // lb:
MakeAssumedShape(Bound && lb)191   static ShapeSpec MakeAssumedShape(Bound &&lb) {
192     return ShapeSpec(std::move(lb), Bound::Colon());
193   }
194   // :
MakeDeferred()195   static ShapeSpec MakeDeferred() {
196     return ShapeSpec(Bound::Colon(), Bound::Colon());
197   }
198   // 1:*
MakeImplied()199   static ShapeSpec MakeImplied() { return ShapeSpec(Bound{1}, Bound::Star()); }
200   // lb:*
MakeImplied(Bound && lb)201   static ShapeSpec MakeImplied(Bound &&lb) {
202     return ShapeSpec(std::move(lb), Bound::Star());
203   }
204   // ..
MakeAssumedRank()205   static ShapeSpec MakeAssumedRank() {
206     return ShapeSpec(Bound::Star(), Bound::Star());
207   }
208 
209   ShapeSpec(const ShapeSpec &) = default;
210   ShapeSpec(ShapeSpec &&) = default;
211   ShapeSpec &operator=(const ShapeSpec &) = default;
212   ShapeSpec &operator=(ShapeSpec &&) = default;
213 
lbound()214   Bound &lbound() { return lb_; }
lbound()215   const Bound &lbound() const { return lb_; }
ubound()216   Bound &ubound() { return ub_; }
ubound()217   const Bound &ubound() const { return ub_; }
218 
219 private:
ShapeSpec(Bound && lb,Bound && ub)220   ShapeSpec(Bound &&lb, Bound &&ub) : lb_{std::move(lb)}, ub_{std::move(ub)} {}
221   Bound lb_;
222   Bound ub_;
223   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ShapeSpec &);
224 };
225 
226 struct ArraySpec : public std::vector<ShapeSpec> {
ArraySpecArraySpec227   ArraySpec() {}
RankArraySpec228   int Rank() const { return size(); }
229   // These names are not exclusive, as some categories cannot be
230   // distinguished without knowing whether the particular symbol
231   // is allocatable, pointer, or a non-allocatable non-pointer dummy.
232   // Use the symbol-based predicates for exact results.
233   inline bool IsExplicitShape() const;
234   inline bool CanBeAssumedShape() const;
235   inline bool CanBeDeferredShape() const;
236   inline bool CanBeImpliedShape() const;
237   inline bool CanBeAssumedSize() const;
238   inline bool IsAssumedRank() const;
239 
240 private:
241   // Check non-empty and predicate is true for each element.
CheckAllArraySpec242   template <typename P> bool CheckAll(P predicate) const {
243     return !empty() && std::all_of(begin(), end(), predicate);
244   }
245 };
246 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ArraySpec &);
247 
248 // Each DerivedTypeSpec has a typeSymbol that has DerivedTypeDetails.
249 // The name may not match the symbol's name in case of a USE rename.
250 class DerivedTypeSpec {
251 public:
252   using RawParameter = std::pair<const parser::Keyword *, ParamValue>;
253   using RawParameters = std::vector<RawParameter>;
254   using ParameterMapType = std::map<SourceName, ParamValue>;
255   DerivedTypeSpec(SourceName, const Symbol &);
256   DerivedTypeSpec(const DerivedTypeSpec &);
257   DerivedTypeSpec(DerivedTypeSpec &&);
258 
name()259   const SourceName &name() const { return name_; }
typeSymbol()260   const Symbol &typeSymbol() const { return typeSymbol_; }
scope()261   const Scope *scope() const { return scope_; }
262   void set_scope(const Scope &);
263   void ReplaceScope(const Scope &);
rawParameters()264   RawParameters &rawParameters() { return rawParameters_; }
parameters()265   const ParameterMapType &parameters() const { return parameters_; }
266 
267   bool MightBeParameterized() const;
268   bool IsForwardReferenced() const;
269   bool HasDefaultInitialization(bool ignoreAllocatable = false) const;
270   bool HasDestruction() const;
271   bool HasFinalization() const;
272 
273   // The "raw" type parameter list is a simple transcription from the
274   // parameter list in the parse tree, built by calling AddRawParamValue().
275   // It can be used with forward-referenced derived types.
276   void AddRawParamValue(const std::optional<parser::Keyword> &, ParamValue &&);
277   // Checks the raw parameter list against the definition of a derived type.
278   // Converts the raw parameter list to a map, naming each actual parameter.
279   void CookParameters(evaluate::FoldingContext &);
280   // Evaluates type parameter expressions.
281   void EvaluateParameters(SemanticsContext &);
282   void AddParamValue(SourceName, ParamValue &&);
283   // Creates a Scope for the type and populates it with component
284   // instantiations that have been specialized with actual type parameter
285   // values, which are cooked &/or evaluated if necessary.
286   void Instantiate(Scope &containingScope);
287 
288   ParamValue *FindParameter(SourceName);
FindParameter(SourceName target)289   const ParamValue *FindParameter(SourceName target) const {
290     auto iter{parameters_.find(target)};
291     if (iter != parameters_.end()) {
292       return &iter->second;
293     } else {
294       return nullptr;
295     }
296   }
297   bool operator==(const DerivedTypeSpec &that) const {
298     return RawEquals(that) && parameters_ == that.parameters_;
299   }
300   bool operator!=(const DerivedTypeSpec &that) const {
301     return !(*this == that);
302   }
303   // For TYPE IS & CLASS IS: kind type parameters must be
304   // explicit and equal, len type parameters are ignored.
305   bool Match(const DerivedTypeSpec &) const;
306   std::string AsFortran() const;
307 
308 private:
309   SourceName name_;
310   const Symbol &typeSymbol_;
311   const Scope *scope_{nullptr}; // same as typeSymbol_.scope() unless PDT
312   bool cooked_{false};
313   bool evaluated_{false};
314   bool instantiated_{false};
315   RawParameters rawParameters_;
316   ParameterMapType parameters_;
RawEquals(const DerivedTypeSpec & that)317   bool RawEquals(const DerivedTypeSpec &that) const {
318     return &typeSymbol_ == &that.typeSymbol_ && cooked_ == that.cooked_ &&
319         rawParameters_ == that.rawParameters_;
320   }
321   friend llvm::raw_ostream &operator<<(
322       llvm::raw_ostream &, const DerivedTypeSpec &);
323 };
324 
325 class DeclTypeSpec {
326 public:
327   enum Category {
328     Numeric,
329     Logical,
330     Character,
331     TypeDerived,
332     ClassDerived,
333     TypeStar,
334     ClassStar
335   };
336 
337   // intrinsic-type-spec or TYPE(intrinsic-type-spec), not character
338   DeclTypeSpec(NumericTypeSpec &&);
339   DeclTypeSpec(LogicalTypeSpec &&);
340   // character
341   DeclTypeSpec(const CharacterTypeSpec &);
342   DeclTypeSpec(CharacterTypeSpec &&);
343   // TYPE(derived-type-spec) or CLASS(derived-type-spec)
344   DeclTypeSpec(Category, const DerivedTypeSpec &);
345   DeclTypeSpec(Category, DerivedTypeSpec &&);
346   // TYPE(*) or CLASS(*)
347   DeclTypeSpec(Category);
348 
349   bool operator==(const DeclTypeSpec &) const;
350   bool operator!=(const DeclTypeSpec &that) const { return !operator==(that); }
351 
category()352   Category category() const { return category_; }
set_category(Category category)353   void set_category(Category category) { category_ = category; }
IsPolymorphic()354   bool IsPolymorphic() const {
355     return category_ == ClassDerived || IsUnlimitedPolymorphic();
356   }
IsUnlimitedPolymorphic()357   bool IsUnlimitedPolymorphic() const {
358     return category_ == TypeStar || category_ == ClassStar;
359   }
IsAssumedType()360   bool IsAssumedType() const { return category_ == TypeStar; }
361   bool IsNumeric(TypeCategory) const;
362   bool IsSequenceType() const;
363   const NumericTypeSpec &numericTypeSpec() const;
364   const LogicalTypeSpec &logicalTypeSpec() const;
characterTypeSpec()365   const CharacterTypeSpec &characterTypeSpec() const {
366     CHECK(category_ == Character);
367     return std::get<CharacterTypeSpec>(typeSpec_);
368   }
derivedTypeSpec()369   const DerivedTypeSpec &derivedTypeSpec() const {
370     CHECK(category_ == TypeDerived || category_ == ClassDerived);
371     return std::get<DerivedTypeSpec>(typeSpec_);
372   }
derivedTypeSpec()373   DerivedTypeSpec &derivedTypeSpec() {
374     CHECK(category_ == TypeDerived || category_ == ClassDerived);
375     return std::get<DerivedTypeSpec>(typeSpec_);
376   }
377 
378   inline IntrinsicTypeSpec *AsIntrinsic();
379   inline const IntrinsicTypeSpec *AsIntrinsic() const;
380   inline DerivedTypeSpec *AsDerived();
381   inline const DerivedTypeSpec *AsDerived() const;
382 
383   std::string AsFortran() const;
384 
385 private:
386   Category category_;
387   std::variant<std::monostate, NumericTypeSpec, LogicalTypeSpec,
388       CharacterTypeSpec, DerivedTypeSpec>
389       typeSpec_;
390 };
391 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DeclTypeSpec &);
392 
393 // This represents a proc-interface in the declaration of a procedure or
394 // procedure component. It comprises a symbol that represents the specific
395 // interface or a decl-type-spec that represents the function return type.
396 class ProcInterface {
397 public:
symbol()398   const Symbol *symbol() const { return symbol_; }
type()399   const DeclTypeSpec *type() const { return type_; }
400   void set_symbol(const Symbol &symbol);
401   void set_type(const DeclTypeSpec &type);
402 
403 private:
404   const Symbol *symbol_{nullptr};
405   const DeclTypeSpec *type_{nullptr};
406 };
407 
408 // Define some member functions here in the header so that they can be used by
409 // lib/Evaluate without link-time dependency on Semantics.
410 
IsExplicitShape()411 inline bool ArraySpec::IsExplicitShape() const {
412   return CheckAll([](const ShapeSpec &x) { return x.ubound().isExplicit(); });
413 }
CanBeAssumedShape()414 inline bool ArraySpec::CanBeAssumedShape() const {
415   return CheckAll([](const ShapeSpec &x) { return x.ubound().isColon(); });
416 }
CanBeDeferredShape()417 inline bool ArraySpec::CanBeDeferredShape() const {
418   return CheckAll([](const ShapeSpec &x) {
419     return x.lbound().isColon() && x.ubound().isColon();
420   });
421 }
CanBeImpliedShape()422 inline bool ArraySpec::CanBeImpliedShape() const {
423   return !IsAssumedRank() &&
424       CheckAll([](const ShapeSpec &x) { return x.ubound().isStar(); });
425 }
CanBeAssumedSize()426 inline bool ArraySpec::CanBeAssumedSize() const {
427   return !empty() && !IsAssumedRank() && back().ubound().isStar() &&
428       std::all_of(begin(), end() - 1,
429           [](const ShapeSpec &x) { return x.ubound().isExplicit(); });
430 }
IsAssumedRank()431 inline bool ArraySpec::IsAssumedRank() const {
432   return Rank() == 1 && front().lbound().isStar();
433 }
434 
AsIntrinsic()435 inline IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() {
436   switch (category_) {
437   case Numeric:
438     return &std::get<NumericTypeSpec>(typeSpec_);
439   case Logical:
440     return &std::get<LogicalTypeSpec>(typeSpec_);
441   case Character:
442     return &std::get<CharacterTypeSpec>(typeSpec_);
443   default:
444     return nullptr;
445   }
446 }
AsIntrinsic()447 inline const IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() const {
448   return const_cast<DeclTypeSpec *>(this)->AsIntrinsic();
449 }
450 
AsDerived()451 inline DerivedTypeSpec *DeclTypeSpec::AsDerived() {
452   switch (category_) {
453   case TypeDerived:
454   case ClassDerived:
455     return &std::get<DerivedTypeSpec>(typeSpec_);
456   default:
457     return nullptr;
458   }
459 }
AsDerived()460 inline const DerivedTypeSpec *DeclTypeSpec::AsDerived() const {
461   return const_cast<DeclTypeSpec *>(this)->AsDerived();
462 }
463 
464 } // namespace Fortran::semantics
465 #endif // FORTRAN_SEMANTICS_TYPE_H_
466