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 ¶meters() 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