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