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