1 // Copyright (c) 2018-2019, NVIDIA CORPORATION.  All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef FORTRAN_SEMANTICS_TYPE_H_
16 #define FORTRAN_SEMANTICS_TYPE_H_
17 
18 #include "../common/Fortran.h"
19 #include "../common/idioms.h"
20 #include "../evaluate/expression.h"
21 #include "../parser/char-block.h"
22 #include <algorithm>
23 #include <iosfwd>
24 #include <map>
25 #include <optional>
26 #include <string>
27 #include <variant>
28 #include <vector>
29 
30 namespace Fortran::semantics {
31 
32 class Scope;
33 class Symbol;
34 
35 /// A SourceName is a name in the cooked character stream,
36 /// i.e. a range of lower-case characters with provenance.
37 using SourceName = parser::CharBlock;
38 using TypeCategory = common::TypeCategory;
39 using SomeExpr = evaluate::Expr<evaluate::SomeType>;
40 using MaybeExpr = std::optional<SomeExpr>;
41 using SomeIntExpr = evaluate::Expr<evaluate::SomeInteger>;
42 using MaybeIntExpr = std::optional<SomeIntExpr>;
43 using SubscriptIntExpr = evaluate::Expr<evaluate::SubscriptInteger>;
44 using MaybeSubscriptIntExpr = std::optional<SubscriptIntExpr>;
45 using KindExpr = SubscriptIntExpr;
46 
47 // An array spec bound: an explicit integer expression or ASSUMED or DEFERRED
48 class Bound {
49 public:
Assumed()50   static Bound Assumed() { return Bound(Category::Assumed); }
Deferred()51   static Bound Deferred() { return Bound(Category::Deferred); }
Bound(MaybeSubscriptIntExpr && expr)52   explicit Bound(MaybeSubscriptIntExpr &&expr) : expr_{std::move(expr)} {}
53   explicit Bound(int bound);
54   Bound(const Bound &) = default;
55   Bound(Bound &&) = default;
56   Bound &operator=(const Bound &) = default;
57   Bound &operator=(Bound &&) = default;
isExplicit()58   bool isExplicit() const { return category_ == Category::Explicit; }
isAssumed()59   bool isAssumed() const { return category_ == Category::Assumed; }
isDeferred()60   bool isDeferred() const { return category_ == Category::Deferred; }
GetExplicit()61   MaybeSubscriptIntExpr &GetExplicit() { return expr_; }
GetExplicit()62   const MaybeSubscriptIntExpr &GetExplicit() const { return expr_; }
SetExplicit(MaybeSubscriptIntExpr && expr)63   void SetExplicit(MaybeSubscriptIntExpr &&expr) {
64     CHECK(isExplicit());
65     expr_ = std::move(expr);
66   }
67 
68 private:
69   enum class Category { Explicit, Deferred, Assumed };
Bound(Category category)70   Bound(Category category) : category_{category} {}
Bound(Category category,MaybeSubscriptIntExpr && expr)71   Bound(Category category, MaybeSubscriptIntExpr &&expr)
72     : category_{category}, expr_{std::move(expr)} {}
73   Category category_{Category::Explicit};
74   MaybeSubscriptIntExpr expr_;
75   friend std::ostream &operator<<(std::ostream &, const Bound &);
76 };
77 
78 // A type parameter value: integer expression or assumed or deferred.
79 class ParamValue {
80 public:
Assumed(common::TypeParamAttr attr)81   static ParamValue Assumed(common::TypeParamAttr attr) {
82     return ParamValue{Category::Assumed, attr};
83   }
Deferred(common::TypeParamAttr attr)84   static ParamValue Deferred(common::TypeParamAttr attr) {
85     return ParamValue{Category::Deferred, attr};
86   }
87   ParamValue(const ParamValue &) = default;
88   explicit ParamValue(MaybeIntExpr &&, common::TypeParamAttr);
89   explicit ParamValue(SomeIntExpr &&, common::TypeParamAttr attr);
90   explicit ParamValue(common::ConstantSubscript, common::TypeParamAttr attr);
isExplicit()91   bool isExplicit() const { return category_ == Category::Explicit; }
isAssumed()92   bool isAssumed() const { return category_ == Category::Assumed; }
isDeferred()93   bool isDeferred() const { return category_ == Category::Deferred; }
GetExplicit()94   const MaybeIntExpr &GetExplicit() const { return expr_; }
95   void SetExplicit(SomeIntExpr &&);
isKind()96   bool isKind() const { return attr_ == common::TypeParamAttr::Kind; }
isLen()97   bool isLen() const { return attr_ == common::TypeParamAttr::Len; }
set_attr(common::TypeParamAttr attr)98   void set_attr(common::TypeParamAttr attr) { attr_ = attr; }
99   bool operator==(const ParamValue &that) const {
100     return category_ == that.category_ && expr_ == that.expr_;
101   }
102   std::string AsFortran() const;
103 
104 private:
105   enum class Category { Explicit, Deferred, Assumed };
ParamValue(Category category,common::TypeParamAttr attr)106   ParamValue(Category category, common::TypeParamAttr attr)
107     : category_{category}, attr_{attr} {}
108   Category category_{Category::Explicit};
109   common::TypeParamAttr attr_{common::TypeParamAttr::Kind};
110   MaybeIntExpr expr_;
111   friend std::ostream &operator<<(std::ostream &, const ParamValue &);
112 };
113 
114 class IntrinsicTypeSpec {
115 public:
category()116   TypeCategory category() const { return category_; }
kind()117   const KindExpr &kind() const { return kind_; }
118   bool operator==(const IntrinsicTypeSpec &x) const {
119     return category_ == x.category_ && kind_ == x.kind_;
120   }
121   bool operator!=(const IntrinsicTypeSpec &x) const { return !operator==(x); }
122   std::string AsFortran() const;
123 
124 protected:
125   IntrinsicTypeSpec(TypeCategory, KindExpr &&);
126 
127 private:
128   TypeCategory category_;
129   KindExpr kind_;
130   friend std::ostream &operator<<(std::ostream &os, const IntrinsicTypeSpec &x);
131 };
132 
133 class NumericTypeSpec : public IntrinsicTypeSpec {
134 public:
NumericTypeSpec(TypeCategory category,KindExpr && kind)135   NumericTypeSpec(TypeCategory category, KindExpr &&kind)
136     : IntrinsicTypeSpec(category, std::move(kind)) {
137     CHECK(common::IsNumericTypeCategory(category));
138   }
139 };
140 
141 class LogicalTypeSpec : public IntrinsicTypeSpec {
142 public:
LogicalTypeSpec(KindExpr && kind)143   explicit LogicalTypeSpec(KindExpr &&kind)
144     : IntrinsicTypeSpec(TypeCategory::Logical, std::move(kind)) {}
145 };
146 
147 class CharacterTypeSpec : public IntrinsicTypeSpec {
148 public:
CharacterTypeSpec(ParamValue && length,KindExpr && kind)149   CharacterTypeSpec(ParamValue &&length, KindExpr &&kind)
150     : IntrinsicTypeSpec(TypeCategory::Character, std::move(kind)),
151       length_{std::move(length)} {}
length()152   const ParamValue &length() const { return length_; }
153   std::string AsFortran() const;
154 
155 private:
156   ParamValue length_;
157   friend std::ostream &operator<<(std::ostream &os, const CharacterTypeSpec &x);
158 };
159 
160 class ShapeSpec {
161 public:
162   // lb:ub
MakeExplicit(Bound && lb,Bound && ub)163   static ShapeSpec MakeExplicit(Bound &&lb, Bound &&ub) {
164     return ShapeSpec(std::move(lb), std::move(ub));
165   }
166   // 1:ub
MakeExplicit(Bound && ub)167   static const ShapeSpec MakeExplicit(Bound &&ub) {
168     return MakeExplicit(Bound{1}, std::move(ub));
169   }
170   // 1:
MakeAssumed()171   static ShapeSpec MakeAssumed() {
172     return ShapeSpec(Bound{1}, Bound::Deferred());
173   }
174   // lb:
MakeAssumed(Bound && lb)175   static ShapeSpec MakeAssumed(Bound &&lb) {
176     return ShapeSpec(std::move(lb), Bound::Deferred());
177   }
178   // :
MakeDeferred()179   static ShapeSpec MakeDeferred() {
180     return ShapeSpec(Bound::Deferred(), Bound::Deferred());
181   }
182   // 1:*
MakeImplied()183   static ShapeSpec MakeImplied() {
184     return ShapeSpec(Bound{1}, Bound::Assumed());
185   }
186   // lb:*
MakeImplied(Bound && lb)187   static ShapeSpec MakeImplied(Bound &&lb) {
188     return ShapeSpec(std::move(lb), Bound::Assumed());
189   }
190   // ..
MakeAssumedRank()191   static ShapeSpec MakeAssumedRank() {
192     return ShapeSpec(Bound::Assumed(), Bound::Assumed());
193   }
194 
195   ShapeSpec(const ShapeSpec &) = default;
196   ShapeSpec(ShapeSpec &&) = default;
197   ShapeSpec &operator=(const ShapeSpec &) = default;
198   ShapeSpec &operator=(ShapeSpec &&) = default;
199 
lbound()200   Bound &lbound() { return lb_; }
lbound()201   const Bound &lbound() const { return lb_; }
ubound()202   Bound &ubound() { return ub_; }
ubound()203   const Bound &ubound() const { return ub_; }
204 
205 private:
ShapeSpec(Bound && lb,Bound && ub)206   ShapeSpec(Bound &&lb, Bound &&ub) : lb_{std::move(lb)}, ub_{std::move(ub)} {}
207   Bound lb_;
208   Bound ub_;
209   friend std::ostream &operator<<(std::ostream &, const ShapeSpec &);
210 };
211 
212 struct ArraySpec : public std::vector<ShapeSpec> {
ArraySpecArraySpec213   ArraySpec() {}
RankArraySpec214   int Rank() const { return size(); }
215   bool IsExplicitShape() const;
216   bool IsAssumedShape() const;
217   bool IsDeferredShape() const;
218   bool IsImpliedShape() const;
219   bool IsAssumedSize() const;
220   bool IsAssumedRank() const;
221 
222 private:
223   // Check non-empty and predicate is true for each element.
CheckAllArraySpec224   template<typename P> bool CheckAll(P predicate) const {
225     return !empty() && std::all_of(begin(), end(), predicate);
226   }
227 };
228 std::ostream &operator<<(std::ostream &, const ArraySpec &);
229 
230 // Each DerivedTypeSpec has a typeSymbol that has DerivedTypeDetails.
231 // The name may not match the symbol's name in case of a USE rename.
232 class DerivedTypeSpec {
233 public:
234   using ParameterMapType = std::map<SourceName, ParamValue>;
235   explicit DerivedTypeSpec(SourceName, const Symbol &);
236   DerivedTypeSpec(const DerivedTypeSpec &);
237   DerivedTypeSpec(DerivedTypeSpec &&);
238 
name()239   const SourceName &name() const { return name_; }
typeSymbol()240   const Symbol &typeSymbol() const { return typeSymbol_; }
scope()241   const Scope *scope() const { return scope_; }
242   void set_scope(const Scope &);
243   void ReplaceScope(const Scope &);
parameters()244   const ParameterMapType &parameters() const { return parameters_; }
245 
246   ParamValue &AddParamValue(SourceName, ParamValue &&);
247   ParamValue *FindParameter(SourceName);
FindParameter(SourceName target)248   const ParamValue *FindParameter(SourceName target) const {
249     auto iter{parameters_.find(target)};
250     if (iter != parameters_.end()) {
251       return &iter->second;
252     } else {
253       return nullptr;
254     }
255   }
256   bool operator==(const DerivedTypeSpec &that) const {
257     return &typeSymbol_ == &that.typeSymbol_ && parameters_ == that.parameters_;
258   }
259   std::string AsFortran() const;
260 
261 private:
262   SourceName name_;
263   const Symbol &typeSymbol_;
264   const Scope *scope_{nullptr};  // same as typeSymbol_.scope() unless PDT
265   ParameterMapType parameters_;
266   friend std::ostream &operator<<(std::ostream &, const DerivedTypeSpec &);
267 };
268 
269 class DeclTypeSpec {
270 public:
271   enum Category {
272     Numeric,
273     Logical,
274     Character,
275     TypeDerived,
276     ClassDerived,
277     TypeStar,
278     ClassStar
279   };
280 
281   // intrinsic-type-spec or TYPE(intrinsic-type-spec), not character
282   DeclTypeSpec(NumericTypeSpec &&);
283   DeclTypeSpec(LogicalTypeSpec &&);
284   // character
285   DeclTypeSpec(const CharacterTypeSpec &);
286   DeclTypeSpec(CharacterTypeSpec &&);
287   // TYPE(derived-type-spec) or CLASS(derived-type-spec)
288   DeclTypeSpec(Category, const DerivedTypeSpec &);
289   DeclTypeSpec(Category, DerivedTypeSpec &&);
290   // TYPE(*) or CLASS(*)
291   DeclTypeSpec(Category);
292 
293   bool operator==(const DeclTypeSpec &) const;
294   bool operator!=(const DeclTypeSpec &that) const { return !operator==(that); }
295 
category()296   Category category() const { return category_; }
set_category(Category category)297   void set_category(Category category) { category_ = category; }
IsPolymorphic()298   bool IsPolymorphic() const {
299     return category_ == ClassDerived || IsUnlimitedPolymorphic();
300   }
IsUnlimitedPolymorphic()301   bool IsUnlimitedPolymorphic() const {
302     return category_ == TypeStar || category_ == ClassStar;
303   }
304   bool IsNumeric(TypeCategory) const;
305   const NumericTypeSpec &numericTypeSpec() const;
306   const LogicalTypeSpec &logicalTypeSpec() const;
characterTypeSpec()307   const CharacterTypeSpec &characterTypeSpec() const {
308     CHECK(category_ == Character);
309     return std::get<CharacterTypeSpec>(typeSpec_);
310   }
derivedTypeSpec()311   const DerivedTypeSpec &derivedTypeSpec() const {
312     CHECK(category_ == TypeDerived || category_ == ClassDerived);
313     return std::get<DerivedTypeSpec>(typeSpec_);
314   }
derivedTypeSpec()315   DerivedTypeSpec &derivedTypeSpec() {
316     CHECK(category_ == TypeDerived || category_ == ClassDerived);
317     return std::get<DerivedTypeSpec>(typeSpec_);
318   }
319 
320   IntrinsicTypeSpec *AsIntrinsic();
AsIntrinsic()321   const IntrinsicTypeSpec *AsIntrinsic() const {
322     switch (category_) {
323     case Numeric: return &std::get<NumericTypeSpec>(typeSpec_);
324     case Logical: return &std::get<LogicalTypeSpec>(typeSpec_);
325     case Character: return &std::get<CharacterTypeSpec>(typeSpec_);
326     default: return nullptr;
327     }
328   }
329 
AsDerived()330   const DerivedTypeSpec *AsDerived() const {
331     switch (category_) {
332     case TypeDerived:
333     case ClassDerived: return &std::get<DerivedTypeSpec>(typeSpec_);
334     default: return nullptr;
335     }
336   }
337 
338   std::string AsFortran() const;
339 
340 private:
341   Category category_;
342   std::variant<std::monostate, NumericTypeSpec, LogicalTypeSpec,
343       CharacterTypeSpec, DerivedTypeSpec>
344       typeSpec_;
345 };
346 std::ostream &operator<<(std::ostream &, const DeclTypeSpec &);
347 
348 // This represents a proc-interface in the declaration of a procedure or
349 // procedure component. It comprises a symbol that represents the specific
350 // interface or a decl-type-spec that represents the function return type.
351 class ProcInterface {
352 public:
symbol()353   const Symbol *symbol() const { return symbol_; }
type()354   const DeclTypeSpec *type() const { return type_; }
355   void set_symbol(const Symbol &symbol);
356   void set_type(const DeclTypeSpec &type);
357 
358 private:
359   const Symbol *symbol_{nullptr};
360   const DeclTypeSpec *type_{nullptr};
361 };
362 }
363 #endif  // FORTRAN_SEMANTICS_TYPE_H_
364