1 //===-- lib/Semantics/type.cpp --------------------------------------------===// 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 #include "flang/Semantics/type.h" 10 #include "flang/Evaluate/fold.h" 11 #include "flang/Parser/characters.h" 12 #include "flang/Semantics/scope.h" 13 #include "flang/Semantics/symbol.h" 14 #include "flang/Semantics/tools.h" 15 #include "llvm/Support/raw_ostream.h" 16 17 namespace Fortran::semantics { 18 19 DerivedTypeSpec::DerivedTypeSpec(SourceName name, const Symbol &typeSymbol) 20 : name_{name}, typeSymbol_{typeSymbol} { 21 CHECK(typeSymbol.has<DerivedTypeDetails>()); 22 } 23 DerivedTypeSpec::DerivedTypeSpec(const DerivedTypeSpec &that) = default; 24 DerivedTypeSpec::DerivedTypeSpec(DerivedTypeSpec &&that) = default; 25 26 void DerivedTypeSpec::set_scope(const Scope &scope) { 27 CHECK(!scope_); 28 ReplaceScope(scope); 29 } 30 void DerivedTypeSpec::ReplaceScope(const Scope &scope) { 31 CHECK(scope.IsDerivedType()); 32 scope_ = &scope; 33 } 34 35 void DerivedTypeSpec::AddRawParamValue( 36 const std::optional<parser::Keyword> &keyword, ParamValue &&value) { 37 CHECK(parameters_.empty()); 38 rawParameters_.emplace_back(keyword ? &*keyword : nullptr, std::move(value)); 39 } 40 41 void DerivedTypeSpec::CookParameters(evaluate::FoldingContext &foldingContext) { 42 if (cooked_) { 43 return; 44 } 45 cooked_ = true; 46 auto &messages{foldingContext.messages()}; 47 if (IsForwardReferenced()) { 48 messages.Say(typeSymbol_.name(), 49 "Derived type '%s' was used but never defined"_err_en_US, 50 typeSymbol_.name()); 51 return; 52 } 53 54 // Parameters of the most deeply nested "base class" come first when the 55 // derived type is an extension. 56 auto parameterNames{OrderParameterNames(typeSymbol_)}; 57 auto parameterDecls{OrderParameterDeclarations(typeSymbol_)}; 58 auto nextNameIter{parameterNames.begin()}; 59 RawParameters raw{std::move(rawParameters_)}; 60 for (auto &[maybeKeyword, value] : raw) { 61 SourceName name; 62 common::TypeParamAttr attr{common::TypeParamAttr::Kind}; 63 if (maybeKeyword) { 64 name = maybeKeyword->v.source; 65 auto it{std::find_if(parameterDecls.begin(), parameterDecls.end(), 66 [&](const Symbol &symbol) { return symbol.name() == name; })}; 67 if (it == parameterDecls.end()) { 68 messages.Say(name, 69 "'%s' is not the name of a parameter for derived type '%s'"_err_en_US, 70 name, typeSymbol_.name()); 71 } else { 72 // Resolve the keyword's symbol 73 maybeKeyword->v.symbol = const_cast<Symbol *>(&it->get()); 74 attr = it->get().get<TypeParamDetails>().attr(); 75 } 76 } else if (nextNameIter != parameterNames.end()) { 77 name = *nextNameIter++; 78 auto it{std::find_if(parameterDecls.begin(), parameterDecls.end(), 79 [&](const Symbol &symbol) { return symbol.name() == name; })}; 80 if (it == parameterDecls.end()) { 81 break; 82 } 83 attr = it->get().get<TypeParamDetails>().attr(); 84 } else { 85 messages.Say(name_, 86 "Too many type parameters given for derived type '%s'"_err_en_US, 87 typeSymbol_.name()); 88 break; 89 } 90 if (FindParameter(name)) { 91 messages.Say(name_, 92 "Multiple values given for type parameter '%s'"_err_en_US, name); 93 } else { 94 value.set_attr(attr); 95 AddParamValue(name, std::move(value)); 96 } 97 } 98 } 99 100 void DerivedTypeSpec::EvaluateParameters( 101 evaluate::FoldingContext &foldingContext) { 102 CookParameters(foldingContext); 103 if (evaluated_) { 104 return; 105 } 106 evaluated_ = true; 107 auto &messages{foldingContext.messages()}; 108 109 // Fold the explicit type parameter value expressions first. Do not 110 // fold them within the scope of the derived type being instantiated; 111 // these expressions cannot use its type parameters. Convert the values 112 // of the expressions to the declared types of the type parameters. 113 auto parameterDecls{OrderParameterDeclarations(typeSymbol_)}; 114 for (const Symbol &symbol : parameterDecls) { 115 const SourceName &name{symbol.name()}; 116 if (ParamValue * paramValue{FindParameter(name)}) { 117 if (const MaybeIntExpr & expr{paramValue->GetExplicit()}) { 118 if (auto converted{evaluate::ConvertToType(symbol, SomeExpr{*expr})}) { 119 SomeExpr folded{ 120 evaluate::Fold(foldingContext, std::move(*converted))}; 121 if (auto *intExpr{std::get_if<SomeIntExpr>(&folded.u)}) { 122 paramValue->SetExplicit(std::move(*intExpr)); 123 continue; 124 } 125 } 126 evaluate::SayWithDeclaration(messages, symbol, 127 "Value of type parameter '%s' (%s) is not convertible to its type"_err_en_US, 128 name, expr->AsFortran()); 129 } 130 } 131 } 132 133 // Default initialization expressions for the derived type's parameters 134 // may reference other parameters so long as the declaration precedes the 135 // use in the expression (10.1.12). This is not necessarily the same 136 // order as "type parameter order" (7.5.3.2). 137 // Type parameter default value expressions are folded in declaration order 138 // within the scope of the derived type so that the values of earlier type 139 // parameters are available for use in the default initialization 140 // expressions of later parameters. 141 auto restorer{foldingContext.WithPDTInstance(*this)}; 142 for (const Symbol &symbol : parameterDecls) { 143 const SourceName &name{symbol.name()}; 144 if (!FindParameter(name)) { 145 const TypeParamDetails &details{symbol.get<TypeParamDetails>()}; 146 if (details.init()) { 147 auto expr{ 148 evaluate::Fold(foldingContext, common::Clone(details.init()))}; 149 AddParamValue(name, ParamValue{std::move(*expr), details.attr()}); 150 } else { 151 messages.Say(name_, 152 "Type parameter '%s' lacks a value and has no default"_err_en_US, 153 name); 154 } 155 } 156 } 157 } 158 159 void DerivedTypeSpec::AddParamValue(SourceName name, ParamValue &&value) { 160 CHECK(cooked_); 161 auto pair{parameters_.insert(std::make_pair(name, std::move(value)))}; 162 CHECK(pair.second); // name was not already present 163 } 164 165 int DerivedTypeSpec::NumLengthParameters() const { 166 int result{0}; 167 for (const auto &pair : parameters_) { 168 if (pair.second.isLen()) { 169 ++result; 170 } 171 } 172 return result; 173 } 174 175 bool DerivedTypeSpec::MightBeParameterized() const { 176 return !cooked_ || !parameters_.empty(); 177 } 178 179 bool DerivedTypeSpec::IsForwardReferenced() const { 180 return typeSymbol_.get<DerivedTypeDetails>().isForwardReferenced(); 181 } 182 183 bool DerivedTypeSpec::HasDefaultInitialization() const { 184 for (const Scope *scope{scope_}; scope; 185 scope = scope->GetDerivedTypeParent()) { 186 for (const auto &pair : *scope) { 187 const Symbol &symbol{*pair.second}; 188 if (IsAllocatable(symbol) || IsInitialized(symbol)) { 189 return true; 190 } 191 } 192 } 193 return false; 194 } 195 196 ParamValue *DerivedTypeSpec::FindParameter(SourceName target) { 197 return const_cast<ParamValue *>( 198 const_cast<const DerivedTypeSpec *>(this)->FindParameter(target)); 199 } 200 201 class InstantiateHelper { 202 public: 203 InstantiateHelper(SemanticsContext &context, Scope &scope) 204 : context_{context}, scope_{scope} {} 205 // Instantiate components from fromScope into scope_ 206 void InstantiateComponents(const Scope &); 207 208 private: 209 evaluate::FoldingContext &foldingContext() { 210 return context_.foldingContext(); 211 } 212 template <typename T> T Fold(T &&expr) { 213 return evaluate::Fold(foldingContext(), std::move(expr)); 214 } 215 void InstantiateComponent(const Symbol &); 216 const DeclTypeSpec *InstantiateType(const Symbol &); 217 const DeclTypeSpec &InstantiateIntrinsicType(const DeclTypeSpec &); 218 DerivedTypeSpec CreateDerivedTypeSpec(const DerivedTypeSpec &, bool); 219 220 SemanticsContext &context_; 221 Scope &scope_; 222 }; 223 224 void DerivedTypeSpec::Instantiate( 225 Scope &containingScope, SemanticsContext &context) { 226 if (instantiated_) { 227 return; 228 } 229 instantiated_ = true; 230 auto &foldingContext{context.foldingContext()}; 231 if (IsForwardReferenced()) { 232 foldingContext.messages().Say(typeSymbol_.name(), 233 "The derived type '%s' was forward-referenced but not defined"_err_en_US, 234 typeSymbol_.name()); 235 return; 236 } 237 CookParameters(foldingContext); 238 EvaluateParameters(foldingContext); 239 const Scope &typeScope{DEREF(typeSymbol_.scope())}; 240 if (!MightBeParameterized()) { 241 scope_ = &typeScope; 242 for (auto &pair : typeScope) { 243 Symbol &symbol{*pair.second}; 244 if (DeclTypeSpec * type{symbol.GetType()}) { 245 if (DerivedTypeSpec * derived{type->AsDerived()}) { 246 if (!(derived->IsForwardReferenced() && 247 IsAllocatableOrPointer(symbol))) { 248 derived->Instantiate(containingScope, context); 249 } 250 } 251 } 252 } 253 return; 254 } 255 Scope &newScope{containingScope.MakeScope(Scope::Kind::DerivedType)}; 256 newScope.set_derivedTypeSpec(*this); 257 ReplaceScope(newScope); 258 for (const Symbol &symbol : OrderParameterDeclarations(typeSymbol_)) { 259 const SourceName &name{symbol.name()}; 260 if (typeScope.find(symbol.name()) != typeScope.end()) { 261 // This type parameter belongs to the derived type itself, not to 262 // one of its ancestors. Put the type parameter expression value 263 // into the new scope as the initialization value for the parameter. 264 if (ParamValue * paramValue{FindParameter(name)}) { 265 const TypeParamDetails &details{symbol.get<TypeParamDetails>()}; 266 paramValue->set_attr(details.attr()); 267 if (MaybeIntExpr expr{paramValue->GetExplicit()}) { 268 // Ensure that any kind type parameters with values are 269 // constant by now. 270 if (details.attr() == common::TypeParamAttr::Kind) { 271 // Any errors in rank and type will have already elicited 272 // messages, so don't pile on by complaining further here. 273 if (auto maybeDynamicType{expr->GetType()}) { 274 if (expr->Rank() == 0 && 275 maybeDynamicType->category() == TypeCategory::Integer) { 276 if (!evaluate::ToInt64(*expr)) { 277 if (auto *msg{foldingContext.messages().Say( 278 "Value of kind type parameter '%s' (%s) is not " 279 "a scalar INTEGER constant"_err_en_US, 280 name, expr->AsFortran())}) { 281 msg->Attach(name, "declared here"_en_US); 282 } 283 } 284 } 285 } 286 } 287 TypeParamDetails instanceDetails{details.attr()}; 288 if (const DeclTypeSpec * type{details.type()}) { 289 instanceDetails.set_type(*type); 290 } 291 instanceDetails.set_init(std::move(*expr)); 292 newScope.try_emplace(name, std::move(instanceDetails)); 293 } 294 } 295 } 296 } 297 // Instantiate every non-parameter symbol from the original derived 298 // type's scope into the new instance. 299 auto restorer{foldingContext.WithPDTInstance(*this)}; 300 newScope.AddSourceRange(typeScope.sourceRange()); 301 InstantiateHelper{context, newScope}.InstantiateComponents(typeScope); 302 } 303 304 void InstantiateHelper::InstantiateComponents(const Scope &fromScope) { 305 for (const auto &pair : fromScope) { 306 InstantiateComponent(*pair.second); 307 } 308 } 309 310 void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) { 311 auto pair{scope_.try_emplace( 312 oldSymbol.name(), oldSymbol.attrs(), common::Clone(oldSymbol.details()))}; 313 Symbol &newSymbol{*pair.first->second}; 314 if (!pair.second) { 315 // Symbol was already present in the scope, which can only happen 316 // in the case of type parameters. 317 CHECK(oldSymbol.has<TypeParamDetails>()); 318 return; 319 } 320 newSymbol.flags() = oldSymbol.flags(); 321 if (auto *details{newSymbol.detailsIf<ObjectEntityDetails>()}) { 322 if (const DeclTypeSpec * newType{InstantiateType(newSymbol)}) { 323 details->ReplaceType(*newType); 324 } 325 details->set_init(Fold(std::move(details->init()))); 326 for (ShapeSpec &dim : details->shape()) { 327 if (dim.lbound().isExplicit()) { 328 dim.lbound().SetExplicit(Fold(std::move(dim.lbound().GetExplicit()))); 329 } 330 if (dim.ubound().isExplicit()) { 331 dim.ubound().SetExplicit(Fold(std::move(dim.ubound().GetExplicit()))); 332 } 333 } 334 for (ShapeSpec &dim : details->coshape()) { 335 if (dim.lbound().isExplicit()) { 336 dim.lbound().SetExplicit(Fold(std::move(dim.lbound().GetExplicit()))); 337 } 338 if (dim.ubound().isExplicit()) { 339 dim.ubound().SetExplicit(Fold(std::move(dim.ubound().GetExplicit()))); 340 } 341 } 342 } 343 } 344 345 const DeclTypeSpec *InstantiateHelper::InstantiateType(const Symbol &symbol) { 346 const DeclTypeSpec *type{symbol.GetType()}; 347 if (!type) { 348 return nullptr; // error has occurred 349 } else if (const DerivedTypeSpec * spec{type->AsDerived()}) { 350 return &FindOrInstantiateDerivedType(scope_, 351 CreateDerivedTypeSpec(*spec, symbol.test(Symbol::Flag::ParentComp)), 352 context_, type->category()); 353 } else if (type->AsIntrinsic()) { 354 return &InstantiateIntrinsicType(*type); 355 } else if (type->category() == DeclTypeSpec::ClassStar) { 356 return type; 357 } else { 358 common::die("InstantiateType: %s", type->AsFortran().c_str()); 359 } 360 } 361 362 // Apply type parameter values to an intrinsic type spec. 363 const DeclTypeSpec &InstantiateHelper::InstantiateIntrinsicType( 364 const DeclTypeSpec &spec) { 365 const IntrinsicTypeSpec &intrinsic{DEREF(spec.AsIntrinsic())}; 366 if (evaluate::ToInt64(intrinsic.kind())) { 367 return spec; // KIND is already a known constant 368 } 369 // The expression was not originally constant, but now it must be so 370 // in the context of a parameterized derived type instantiation. 371 KindExpr copy{Fold(common::Clone(intrinsic.kind()))}; 372 int kind{context_.GetDefaultKind(intrinsic.category())}; 373 if (auto value{evaluate::ToInt64(copy)}) { 374 if (evaluate::IsValidKindOfIntrinsicType(intrinsic.category(), *value)) { 375 kind = *value; 376 } else { 377 foldingContext().messages().Say( 378 "KIND parameter value (%jd) of intrinsic type %s " 379 "did not resolve to a supported value"_err_en_US, 380 *value, 381 parser::ToUpperCaseLetters(EnumToString(intrinsic.category()))); 382 } 383 } 384 switch (spec.category()) { 385 case DeclTypeSpec::Numeric: 386 return scope_.MakeNumericType(intrinsic.category(), KindExpr{kind}); 387 case DeclTypeSpec::Logical: 388 return scope_.MakeLogicalType(KindExpr{kind}); 389 case DeclTypeSpec::Character: 390 return scope_.MakeCharacterType( 391 ParamValue{spec.characterTypeSpec().length()}, KindExpr{kind}); 392 default: 393 CRASH_NO_CASE; 394 } 395 } 396 397 DerivedTypeSpec InstantiateHelper::CreateDerivedTypeSpec( 398 const DerivedTypeSpec &spec, bool isParentComp) { 399 DerivedTypeSpec result{spec}; 400 result.CookParameters(foldingContext()); // enables AddParamValue() 401 if (isParentComp) { 402 // Forward any explicit type parameter values from the 403 // derived type spec under instantiation that define type parameters 404 // of the parent component to the derived type spec of the 405 // parent component. 406 const DerivedTypeSpec &instanceSpec{DEREF(foldingContext().pdtInstance())}; 407 for (const auto &[name, value] : instanceSpec.parameters()) { 408 if (scope_.find(name) == scope_.end()) { 409 result.AddParamValue(name, ParamValue{value}); 410 } 411 } 412 } 413 return result; 414 } 415 416 std::string DerivedTypeSpec::AsFortran() const { 417 std::string buf; 418 llvm::raw_string_ostream ss{buf}; 419 ss << name_; 420 if (!rawParameters_.empty()) { 421 CHECK(parameters_.empty()); 422 ss << '('; 423 bool first = true; 424 for (const auto &[maybeKeyword, value] : rawParameters_) { 425 if (first) { 426 first = false; 427 } else { 428 ss << ','; 429 } 430 if (maybeKeyword) { 431 ss << maybeKeyword->v.source.ToString() << '='; 432 } 433 ss << value.AsFortran(); 434 } 435 ss << ')'; 436 } else if (!parameters_.empty()) { 437 ss << '('; 438 bool first = true; 439 for (const auto &[name, value] : parameters_) { 440 if (first) { 441 first = false; 442 } else { 443 ss << ','; 444 } 445 ss << name.ToString() << '=' << value.AsFortran(); 446 } 447 ss << ')'; 448 } 449 return ss.str(); 450 } 451 452 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const DerivedTypeSpec &x) { 453 return o << x.AsFortran(); 454 } 455 456 Bound::Bound(int bound) : expr_{bound} {} 457 458 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const Bound &x) { 459 if (x.isAssumed()) { 460 o << '*'; 461 } else if (x.isDeferred()) { 462 o << ':'; 463 } else if (x.expr_) { 464 x.expr_->AsFortran(o); 465 } else { 466 o << "<no-expr>"; 467 } 468 return o; 469 } 470 471 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const ShapeSpec &x) { 472 if (x.lb_.isAssumed()) { 473 CHECK(x.ub_.isAssumed()); 474 o << ".."; 475 } else { 476 if (!x.lb_.isDeferred()) { 477 o << x.lb_; 478 } 479 o << ':'; 480 if (!x.ub_.isDeferred()) { 481 o << x.ub_; 482 } 483 } 484 return o; 485 } 486 487 bool ArraySpec::IsExplicitShape() const { 488 return CheckAll([](const ShapeSpec &x) { return x.ubound().isExplicit(); }); 489 } 490 bool ArraySpec::IsAssumedShape() const { 491 return CheckAll([](const ShapeSpec &x) { return x.ubound().isDeferred(); }); 492 } 493 bool ArraySpec::IsDeferredShape() const { 494 return CheckAll([](const ShapeSpec &x) { 495 return x.lbound().isDeferred() && x.ubound().isDeferred(); 496 }); 497 } 498 bool ArraySpec::IsImpliedShape() const { 499 return !IsAssumedRank() && 500 CheckAll([](const ShapeSpec &x) { return x.ubound().isAssumed(); }); 501 } 502 bool ArraySpec::IsAssumedSize() const { 503 return !empty() && !IsAssumedRank() && back().ubound().isAssumed() && 504 std::all_of(begin(), end() - 1, 505 [](const ShapeSpec &x) { return x.ubound().isExplicit(); }); 506 } 507 bool ArraySpec::IsAssumedRank() const { 508 return Rank() == 1 && front().lbound().isAssumed(); 509 } 510 bool ArraySpec::IsConstantShape() const { 511 return CheckAll([](const ShapeSpec &x) { 512 const auto &lb{x.lbound().GetExplicit()}; 513 const auto &ub{x.ubound().GetExplicit()}; 514 return lb && ub && IsConstantExpr(*lb) && IsConstantExpr(*ub); 515 }); 516 } 517 518 llvm::raw_ostream &operator<<( 519 llvm::raw_ostream &os, const ArraySpec &arraySpec) { 520 char sep{'('}; 521 for (auto &shape : arraySpec) { 522 os << sep << shape; 523 sep = ','; 524 } 525 if (sep == ',') { 526 os << ')'; 527 } 528 return os; 529 } 530 531 ParamValue::ParamValue(MaybeIntExpr &&expr, common::TypeParamAttr attr) 532 : attr_{attr}, expr_{std::move(expr)} {} 533 ParamValue::ParamValue(SomeIntExpr &&expr, common::TypeParamAttr attr) 534 : attr_{attr}, expr_{std::move(expr)} {} 535 ParamValue::ParamValue( 536 common::ConstantSubscript value, common::TypeParamAttr attr) 537 : ParamValue(SomeIntExpr{evaluate::Expr<evaluate::SubscriptInteger>{value}}, 538 attr) {} 539 540 void ParamValue::SetExplicit(SomeIntExpr &&x) { 541 category_ = Category::Explicit; 542 expr_ = std::move(x); 543 } 544 545 std::string ParamValue::AsFortran() const { 546 switch (category_) { 547 SWITCH_COVERS_ALL_CASES 548 case Category::Assumed: 549 return "*"; 550 case Category::Deferred: 551 return ":"; 552 case Category::Explicit: 553 if (expr_) { 554 std::string buf; 555 llvm::raw_string_ostream ss{buf}; 556 expr_->AsFortran(ss); 557 return ss.str(); 558 } else { 559 return ""; 560 } 561 } 562 } 563 564 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const ParamValue &x) { 565 return o << x.AsFortran(); 566 } 567 568 IntrinsicTypeSpec::IntrinsicTypeSpec(TypeCategory category, KindExpr &&kind) 569 : category_{category}, kind_{std::move(kind)} { 570 CHECK(category != TypeCategory::Derived); 571 } 572 573 static std::string KindAsFortran(const KindExpr &kind) { 574 std::string buf; 575 llvm::raw_string_ostream ss{buf}; 576 if (auto k{evaluate::ToInt64(kind)}) { 577 ss << *k; // emit unsuffixed kind code 578 } else { 579 kind.AsFortran(ss); 580 } 581 return ss.str(); 582 } 583 584 std::string IntrinsicTypeSpec::AsFortran() const { 585 return parser::ToUpperCaseLetters(common::EnumToString(category_)) + '(' + 586 KindAsFortran(kind_) + ')'; 587 } 588 589 llvm::raw_ostream &operator<<( 590 llvm::raw_ostream &os, const IntrinsicTypeSpec &x) { 591 return os << x.AsFortran(); 592 } 593 594 std::string CharacterTypeSpec::AsFortran() const { 595 return "CHARACTER(" + length_.AsFortran() + ',' + KindAsFortran(kind()) + ')'; 596 } 597 598 llvm::raw_ostream &operator<<( 599 llvm::raw_ostream &os, const CharacterTypeSpec &x) { 600 return os << x.AsFortran(); 601 } 602 603 DeclTypeSpec::DeclTypeSpec(NumericTypeSpec &&typeSpec) 604 : category_{Numeric}, typeSpec_{std::move(typeSpec)} {} 605 DeclTypeSpec::DeclTypeSpec(LogicalTypeSpec &&typeSpec) 606 : category_{Logical}, typeSpec_{std::move(typeSpec)} {} 607 DeclTypeSpec::DeclTypeSpec(const CharacterTypeSpec &typeSpec) 608 : category_{Character}, typeSpec_{typeSpec} {} 609 DeclTypeSpec::DeclTypeSpec(CharacterTypeSpec &&typeSpec) 610 : category_{Character}, typeSpec_{std::move(typeSpec)} {} 611 DeclTypeSpec::DeclTypeSpec(Category category, const DerivedTypeSpec &typeSpec) 612 : category_{category}, typeSpec_{typeSpec} { 613 CHECK(category == TypeDerived || category == ClassDerived); 614 } 615 DeclTypeSpec::DeclTypeSpec(Category category, DerivedTypeSpec &&typeSpec) 616 : category_{category}, typeSpec_{std::move(typeSpec)} { 617 CHECK(category == TypeDerived || category == ClassDerived); 618 } 619 DeclTypeSpec::DeclTypeSpec(Category category) : category_{category} { 620 CHECK(category == TypeStar || category == ClassStar); 621 } 622 bool DeclTypeSpec::IsNumeric(TypeCategory tc) const { 623 return category_ == Numeric && numericTypeSpec().category() == tc; 624 } 625 bool DeclTypeSpec::IsSequenceType() const { 626 if (const DerivedTypeSpec * derivedType{AsDerived()}) { 627 const auto *typeDetails{ 628 derivedType->typeSymbol().detailsIf<DerivedTypeDetails>()}; 629 return typeDetails && typeDetails->sequence(); 630 } 631 return false; 632 } 633 634 IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() { 635 switch (category_) { 636 case Numeric: 637 return &std::get<NumericTypeSpec>(typeSpec_); 638 case Logical: 639 return &std::get<LogicalTypeSpec>(typeSpec_); 640 case Character: 641 return &std::get<CharacterTypeSpec>(typeSpec_); 642 default: 643 return nullptr; 644 } 645 } 646 const IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() const { 647 return const_cast<DeclTypeSpec *>(this)->AsIntrinsic(); 648 } 649 650 DerivedTypeSpec *DeclTypeSpec::AsDerived() { 651 switch (category_) { 652 case TypeDerived: 653 case ClassDerived: 654 return &std::get<DerivedTypeSpec>(typeSpec_); 655 default: 656 return nullptr; 657 } 658 } 659 const DerivedTypeSpec *DeclTypeSpec::AsDerived() const { 660 return const_cast<DeclTypeSpec *>(this)->AsDerived(); 661 } 662 663 const NumericTypeSpec &DeclTypeSpec::numericTypeSpec() const { 664 CHECK(category_ == Numeric); 665 return std::get<NumericTypeSpec>(typeSpec_); 666 } 667 const LogicalTypeSpec &DeclTypeSpec::logicalTypeSpec() const { 668 CHECK(category_ == Logical); 669 return std::get<LogicalTypeSpec>(typeSpec_); 670 } 671 bool DeclTypeSpec::operator==(const DeclTypeSpec &that) const { 672 return category_ == that.category_ && typeSpec_ == that.typeSpec_; 673 } 674 675 std::string DeclTypeSpec::AsFortran() const { 676 switch (category_) { 677 SWITCH_COVERS_ALL_CASES 678 case Numeric: 679 return numericTypeSpec().AsFortran(); 680 case Logical: 681 return logicalTypeSpec().AsFortran(); 682 case Character: 683 return characterTypeSpec().AsFortran(); 684 case TypeDerived: 685 return "TYPE(" + derivedTypeSpec().AsFortran() + ')'; 686 case ClassDerived: 687 return "CLASS(" + derivedTypeSpec().AsFortran() + ')'; 688 case TypeStar: 689 return "TYPE(*)"; 690 case ClassStar: 691 return "CLASS(*)"; 692 } 693 } 694 695 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const DeclTypeSpec &x) { 696 return o << x.AsFortran(); 697 } 698 699 void ProcInterface::set_symbol(const Symbol &symbol) { 700 CHECK(!type_); 701 symbol_ = &symbol; 702 } 703 void ProcInterface::set_type(const DeclTypeSpec &type) { 704 CHECK(!symbol_); 705 type_ = &type; 706 } 707 } // namespace Fortran::semantics 708