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 if (!symbol.test(Symbol::Flag::Error)) { 127 evaluate::SayWithDeclaration(messages, symbol, 128 "Value of type parameter '%s' (%s) is not convertible to its" 129 " type"_err_en_US, 130 name, expr->AsFortran()); 131 } 132 } 133 } 134 } 135 136 // Default initialization expressions for the derived type's parameters 137 // may reference other parameters so long as the declaration precedes the 138 // use in the expression (10.1.12). This is not necessarily the same 139 // order as "type parameter order" (7.5.3.2). 140 // Type parameter default value expressions are folded in declaration order 141 // within the scope of the derived type so that the values of earlier type 142 // parameters are available for use in the default initialization 143 // expressions of later parameters. 144 auto restorer{foldingContext.WithPDTInstance(*this)}; 145 for (const Symbol &symbol : parameterDecls) { 146 const SourceName &name{symbol.name()}; 147 if (!FindParameter(name)) { 148 const TypeParamDetails &details{symbol.get<TypeParamDetails>()}; 149 if (details.init()) { 150 auto expr{ 151 evaluate::Fold(foldingContext, common::Clone(details.init()))}; 152 AddParamValue(name, ParamValue{std::move(*expr), details.attr()}); 153 } else if (!symbol.test(Symbol::Flag::Error)) { 154 messages.Say(name_, 155 "Type parameter '%s' lacks a value and has no default"_err_en_US, 156 name); 157 } 158 } 159 } 160 } 161 162 void DerivedTypeSpec::AddParamValue(SourceName name, ParamValue &&value) { 163 CHECK(cooked_); 164 auto pair{parameters_.insert(std::make_pair(name, std::move(value)))}; 165 CHECK(pair.second); // name was not already present 166 } 167 168 bool DerivedTypeSpec::MightBeParameterized() const { 169 return !cooked_ || !parameters_.empty(); 170 } 171 172 bool DerivedTypeSpec::IsForwardReferenced() const { 173 return typeSymbol_.get<DerivedTypeDetails>().isForwardReferenced(); 174 } 175 176 bool DerivedTypeSpec::HasDefaultInitialization() const { 177 for (const Scope *scope{scope_}; scope; 178 scope = scope->GetDerivedTypeParent()) { 179 for (const auto &pair : *scope) { 180 const Symbol &symbol{*pair.second}; 181 if (IsAllocatable(symbol) || IsInitialized(symbol)) { 182 return true; 183 } 184 } 185 } 186 return false; 187 } 188 189 ParamValue *DerivedTypeSpec::FindParameter(SourceName target) { 190 return const_cast<ParamValue *>( 191 const_cast<const DerivedTypeSpec *>(this)->FindParameter(target)); 192 } 193 194 class InstantiateHelper { 195 public: 196 InstantiateHelper(SemanticsContext &context, Scope &scope) 197 : context_{context}, scope_{scope} {} 198 // Instantiate components from fromScope into scope_ 199 void InstantiateComponents(const Scope &); 200 201 private: 202 evaluate::FoldingContext &foldingContext() { 203 return context_.foldingContext(); 204 } 205 template <typename T> T Fold(T &&expr) { 206 return evaluate::Fold(foldingContext(), std::move(expr)); 207 } 208 void InstantiateComponent(const Symbol &); 209 const DeclTypeSpec *InstantiateType(const Symbol &); 210 const DeclTypeSpec &InstantiateIntrinsicType(const DeclTypeSpec &); 211 DerivedTypeSpec CreateDerivedTypeSpec(const DerivedTypeSpec &, bool); 212 213 SemanticsContext &context_; 214 Scope &scope_; 215 }; 216 217 void DerivedTypeSpec::Instantiate( 218 Scope &containingScope, SemanticsContext &context) { 219 if (instantiated_) { 220 return; 221 } 222 instantiated_ = true; 223 auto &foldingContext{context.foldingContext()}; 224 if (IsForwardReferenced()) { 225 foldingContext.messages().Say(typeSymbol_.name(), 226 "The derived type '%s' was forward-referenced but not defined"_err_en_US, 227 typeSymbol_.name()); 228 return; 229 } 230 CookParameters(foldingContext); 231 EvaluateParameters(foldingContext); 232 const Scope &typeScope{DEREF(typeSymbol_.scope())}; 233 if (!MightBeParameterized()) { 234 scope_ = &typeScope; 235 for (auto &pair : typeScope) { 236 Symbol &symbol{*pair.second}; 237 if (DeclTypeSpec * type{symbol.GetType()}) { 238 if (DerivedTypeSpec * derived{type->AsDerived()}) { 239 if (!(derived->IsForwardReferenced() && 240 IsAllocatableOrPointer(symbol))) { 241 derived->Instantiate(containingScope, context); 242 } 243 } 244 } 245 } 246 return; 247 } 248 Scope &newScope{containingScope.MakeScope(Scope::Kind::DerivedType)}; 249 newScope.set_derivedTypeSpec(*this); 250 ReplaceScope(newScope); 251 for (const Symbol &symbol : OrderParameterDeclarations(typeSymbol_)) { 252 const SourceName &name{symbol.name()}; 253 if (typeScope.find(symbol.name()) != typeScope.end()) { 254 // This type parameter belongs to the derived type itself, not to 255 // one of its ancestors. Put the type parameter expression value 256 // into the new scope as the initialization value for the parameter. 257 if (ParamValue * paramValue{FindParameter(name)}) { 258 const TypeParamDetails &details{symbol.get<TypeParamDetails>()}; 259 paramValue->set_attr(details.attr()); 260 if (MaybeIntExpr expr{paramValue->GetExplicit()}) { 261 // Ensure that any kind type parameters with values are 262 // constant by now. 263 if (details.attr() == common::TypeParamAttr::Kind) { 264 // Any errors in rank and type will have already elicited 265 // messages, so don't pile on by complaining further here. 266 if (auto maybeDynamicType{expr->GetType()}) { 267 if (expr->Rank() == 0 && 268 maybeDynamicType->category() == TypeCategory::Integer) { 269 if (!evaluate::ToInt64(*expr)) { 270 if (auto *msg{foldingContext.messages().Say( 271 "Value of kind type parameter '%s' (%s) is not " 272 "a scalar INTEGER constant"_err_en_US, 273 name, expr->AsFortran())}) { 274 msg->Attach(name, "declared here"_en_US); 275 } 276 } 277 } 278 } 279 } 280 TypeParamDetails instanceDetails{details.attr()}; 281 if (const DeclTypeSpec * type{details.type()}) { 282 instanceDetails.set_type(*type); 283 } 284 instanceDetails.set_init(std::move(*expr)); 285 newScope.try_emplace(name, std::move(instanceDetails)); 286 } 287 } 288 } 289 } 290 // Instantiate every non-parameter symbol from the original derived 291 // type's scope into the new instance. 292 auto restorer{foldingContext.WithPDTInstance(*this)}; 293 newScope.AddSourceRange(typeScope.sourceRange()); 294 InstantiateHelper{context, newScope}.InstantiateComponents(typeScope); 295 } 296 297 void InstantiateHelper::InstantiateComponents(const Scope &fromScope) { 298 for (const auto &pair : fromScope) { 299 InstantiateComponent(*pair.second); 300 } 301 } 302 303 void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) { 304 auto pair{scope_.try_emplace( 305 oldSymbol.name(), oldSymbol.attrs(), common::Clone(oldSymbol.details()))}; 306 Symbol &newSymbol{*pair.first->second}; 307 if (!pair.second) { 308 // Symbol was already present in the scope, which can only happen 309 // in the case of type parameters. 310 CHECK(oldSymbol.has<TypeParamDetails>()); 311 return; 312 } 313 newSymbol.flags() = oldSymbol.flags(); 314 if (auto *details{newSymbol.detailsIf<ObjectEntityDetails>()}) { 315 if (const DeclTypeSpec * newType{InstantiateType(newSymbol)}) { 316 details->ReplaceType(*newType); 317 } 318 details->set_init(Fold(std::move(details->init()))); 319 for (ShapeSpec &dim : details->shape()) { 320 if (dim.lbound().isExplicit()) { 321 dim.lbound().SetExplicit(Fold(std::move(dim.lbound().GetExplicit()))); 322 } 323 if (dim.ubound().isExplicit()) { 324 dim.ubound().SetExplicit(Fold(std::move(dim.ubound().GetExplicit()))); 325 } 326 } 327 for (ShapeSpec &dim : details->coshape()) { 328 if (dim.lbound().isExplicit()) { 329 dim.lbound().SetExplicit(Fold(std::move(dim.lbound().GetExplicit()))); 330 } 331 if (dim.ubound().isExplicit()) { 332 dim.ubound().SetExplicit(Fold(std::move(dim.ubound().GetExplicit()))); 333 } 334 } 335 } 336 } 337 338 const DeclTypeSpec *InstantiateHelper::InstantiateType(const Symbol &symbol) { 339 const DeclTypeSpec *type{symbol.GetType()}; 340 if (!type) { 341 return nullptr; // error has occurred 342 } else if (const DerivedTypeSpec * spec{type->AsDerived()}) { 343 return &FindOrInstantiateDerivedType(scope_, 344 CreateDerivedTypeSpec(*spec, symbol.test(Symbol::Flag::ParentComp)), 345 context_, type->category()); 346 } else if (type->AsIntrinsic()) { 347 return &InstantiateIntrinsicType(*type); 348 } else if (type->category() == DeclTypeSpec::ClassStar) { 349 return type; 350 } else { 351 common::die("InstantiateType: %s", type->AsFortran().c_str()); 352 } 353 } 354 355 // Apply type parameter values to an intrinsic type spec. 356 const DeclTypeSpec &InstantiateHelper::InstantiateIntrinsicType( 357 const DeclTypeSpec &spec) { 358 const IntrinsicTypeSpec &intrinsic{DEREF(spec.AsIntrinsic())}; 359 if (evaluate::ToInt64(intrinsic.kind())) { 360 return spec; // KIND is already a known constant 361 } 362 // The expression was not originally constant, but now it must be so 363 // in the context of a parameterized derived type instantiation. 364 KindExpr copy{Fold(common::Clone(intrinsic.kind()))}; 365 int kind{context_.GetDefaultKind(intrinsic.category())}; 366 if (auto value{evaluate::ToInt64(copy)}) { 367 if (evaluate::IsValidKindOfIntrinsicType(intrinsic.category(), *value)) { 368 kind = *value; 369 } else { 370 foldingContext().messages().Say( 371 "KIND parameter value (%jd) of intrinsic type %s " 372 "did not resolve to a supported value"_err_en_US, 373 *value, 374 parser::ToUpperCaseLetters(EnumToString(intrinsic.category()))); 375 } 376 } 377 switch (spec.category()) { 378 case DeclTypeSpec::Numeric: 379 return scope_.MakeNumericType(intrinsic.category(), KindExpr{kind}); 380 case DeclTypeSpec::Logical: 381 return scope_.MakeLogicalType(KindExpr{kind}); 382 case DeclTypeSpec::Character: 383 return scope_.MakeCharacterType( 384 ParamValue{spec.characterTypeSpec().length()}, KindExpr{kind}); 385 default: 386 CRASH_NO_CASE; 387 } 388 } 389 390 DerivedTypeSpec InstantiateHelper::CreateDerivedTypeSpec( 391 const DerivedTypeSpec &spec, bool isParentComp) { 392 DerivedTypeSpec result{spec}; 393 result.CookParameters(foldingContext()); // enables AddParamValue() 394 if (isParentComp) { 395 // Forward any explicit type parameter values from the 396 // derived type spec under instantiation that define type parameters 397 // of the parent component to the derived type spec of the 398 // parent component. 399 const DerivedTypeSpec &instanceSpec{DEREF(foldingContext().pdtInstance())}; 400 for (const auto &[name, value] : instanceSpec.parameters()) { 401 if (scope_.find(name) == scope_.end()) { 402 result.AddParamValue(name, ParamValue{value}); 403 } 404 } 405 } 406 return result; 407 } 408 409 std::string DerivedTypeSpec::AsFortran() const { 410 std::string buf; 411 llvm::raw_string_ostream ss{buf}; 412 ss << name_; 413 if (!rawParameters_.empty()) { 414 CHECK(parameters_.empty()); 415 ss << '('; 416 bool first = true; 417 for (const auto &[maybeKeyword, value] : rawParameters_) { 418 if (first) { 419 first = false; 420 } else { 421 ss << ','; 422 } 423 if (maybeKeyword) { 424 ss << maybeKeyword->v.source.ToString() << '='; 425 } 426 ss << value.AsFortran(); 427 } 428 ss << ')'; 429 } else if (!parameters_.empty()) { 430 ss << '('; 431 bool first = true; 432 for (const auto &[name, value] : parameters_) { 433 if (first) { 434 first = false; 435 } else { 436 ss << ','; 437 } 438 ss << name.ToString() << '=' << value.AsFortran(); 439 } 440 ss << ')'; 441 } 442 return ss.str(); 443 } 444 445 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const DerivedTypeSpec &x) { 446 return o << x.AsFortran(); 447 } 448 449 Bound::Bound(int bound) : expr_{bound} {} 450 451 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const Bound &x) { 452 if (x.isAssumed()) { 453 o << '*'; 454 } else if (x.isDeferred()) { 455 o << ':'; 456 } else if (x.expr_) { 457 x.expr_->AsFortran(o); 458 } else { 459 o << "<no-expr>"; 460 } 461 return o; 462 } 463 464 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const ShapeSpec &x) { 465 if (x.lb_.isAssumed()) { 466 CHECK(x.ub_.isAssumed()); 467 o << ".."; 468 } else { 469 if (!x.lb_.isDeferred()) { 470 o << x.lb_; 471 } 472 o << ':'; 473 if (!x.ub_.isDeferred()) { 474 o << x.ub_; 475 } 476 } 477 return o; 478 } 479 480 llvm::raw_ostream &operator<<( 481 llvm::raw_ostream &os, const ArraySpec &arraySpec) { 482 char sep{'('}; 483 for (auto &shape : arraySpec) { 484 os << sep << shape; 485 sep = ','; 486 } 487 if (sep == ',') { 488 os << ')'; 489 } 490 return os; 491 } 492 493 ParamValue::ParamValue(MaybeIntExpr &&expr, common::TypeParamAttr attr) 494 : attr_{attr}, expr_{std::move(expr)} {} 495 ParamValue::ParamValue(SomeIntExpr &&expr, common::TypeParamAttr attr) 496 : attr_{attr}, expr_{std::move(expr)} {} 497 ParamValue::ParamValue( 498 common::ConstantSubscript value, common::TypeParamAttr attr) 499 : ParamValue(SomeIntExpr{evaluate::Expr<evaluate::SubscriptInteger>{value}}, 500 attr) {} 501 502 void ParamValue::SetExplicit(SomeIntExpr &&x) { 503 category_ = Category::Explicit; 504 expr_ = std::move(x); 505 } 506 507 std::string ParamValue::AsFortran() const { 508 switch (category_) { 509 SWITCH_COVERS_ALL_CASES 510 case Category::Assumed: 511 return "*"; 512 case Category::Deferred: 513 return ":"; 514 case Category::Explicit: 515 if (expr_) { 516 std::string buf; 517 llvm::raw_string_ostream ss{buf}; 518 expr_->AsFortran(ss); 519 return ss.str(); 520 } else { 521 return ""; 522 } 523 } 524 } 525 526 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const ParamValue &x) { 527 return o << x.AsFortran(); 528 } 529 530 IntrinsicTypeSpec::IntrinsicTypeSpec(TypeCategory category, KindExpr &&kind) 531 : category_{category}, kind_{std::move(kind)} { 532 CHECK(category != TypeCategory::Derived); 533 } 534 535 static std::string KindAsFortran(const KindExpr &kind) { 536 std::string buf; 537 llvm::raw_string_ostream ss{buf}; 538 if (auto k{evaluate::ToInt64(kind)}) { 539 ss << *k; // emit unsuffixed kind code 540 } else { 541 kind.AsFortran(ss); 542 } 543 return ss.str(); 544 } 545 546 std::string IntrinsicTypeSpec::AsFortran() const { 547 return parser::ToUpperCaseLetters(common::EnumToString(category_)) + '(' + 548 KindAsFortran(kind_) + ')'; 549 } 550 551 llvm::raw_ostream &operator<<( 552 llvm::raw_ostream &os, const IntrinsicTypeSpec &x) { 553 return os << x.AsFortran(); 554 } 555 556 std::string CharacterTypeSpec::AsFortran() const { 557 return "CHARACTER(" + length_.AsFortran() + ',' + KindAsFortran(kind()) + ')'; 558 } 559 560 llvm::raw_ostream &operator<<( 561 llvm::raw_ostream &os, const CharacterTypeSpec &x) { 562 return os << x.AsFortran(); 563 } 564 565 DeclTypeSpec::DeclTypeSpec(NumericTypeSpec &&typeSpec) 566 : category_{Numeric}, typeSpec_{std::move(typeSpec)} {} 567 DeclTypeSpec::DeclTypeSpec(LogicalTypeSpec &&typeSpec) 568 : category_{Logical}, typeSpec_{std::move(typeSpec)} {} 569 DeclTypeSpec::DeclTypeSpec(const CharacterTypeSpec &typeSpec) 570 : category_{Character}, typeSpec_{typeSpec} {} 571 DeclTypeSpec::DeclTypeSpec(CharacterTypeSpec &&typeSpec) 572 : category_{Character}, typeSpec_{std::move(typeSpec)} {} 573 DeclTypeSpec::DeclTypeSpec(Category category, const DerivedTypeSpec &typeSpec) 574 : category_{category}, typeSpec_{typeSpec} { 575 CHECK(category == TypeDerived || category == ClassDerived); 576 } 577 DeclTypeSpec::DeclTypeSpec(Category category, DerivedTypeSpec &&typeSpec) 578 : category_{category}, typeSpec_{std::move(typeSpec)} { 579 CHECK(category == TypeDerived || category == ClassDerived); 580 } 581 DeclTypeSpec::DeclTypeSpec(Category category) : category_{category} { 582 CHECK(category == TypeStar || category == ClassStar); 583 } 584 bool DeclTypeSpec::IsNumeric(TypeCategory tc) const { 585 return category_ == Numeric && numericTypeSpec().category() == tc; 586 } 587 bool DeclTypeSpec::IsSequenceType() const { 588 if (const DerivedTypeSpec * derivedType{AsDerived()}) { 589 const auto *typeDetails{ 590 derivedType->typeSymbol().detailsIf<DerivedTypeDetails>()}; 591 return typeDetails && typeDetails->sequence(); 592 } 593 return false; 594 } 595 596 const NumericTypeSpec &DeclTypeSpec::numericTypeSpec() const { 597 CHECK(category_ == Numeric); 598 return std::get<NumericTypeSpec>(typeSpec_); 599 } 600 const LogicalTypeSpec &DeclTypeSpec::logicalTypeSpec() const { 601 CHECK(category_ == Logical); 602 return std::get<LogicalTypeSpec>(typeSpec_); 603 } 604 bool DeclTypeSpec::operator==(const DeclTypeSpec &that) const { 605 return category_ == that.category_ && typeSpec_ == that.typeSpec_; 606 } 607 608 std::string DeclTypeSpec::AsFortran() const { 609 switch (category_) { 610 SWITCH_COVERS_ALL_CASES 611 case Numeric: 612 return numericTypeSpec().AsFortran(); 613 case Logical: 614 return logicalTypeSpec().AsFortran(); 615 case Character: 616 return characterTypeSpec().AsFortran(); 617 case TypeDerived: 618 return "TYPE(" + derivedTypeSpec().AsFortran() + ')'; 619 case ClassDerived: 620 return "CLASS(" + derivedTypeSpec().AsFortran() + ')'; 621 case TypeStar: 622 return "TYPE(*)"; 623 case ClassStar: 624 return "CLASS(*)"; 625 } 626 } 627 628 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const DeclTypeSpec &x) { 629 return o << x.AsFortran(); 630 } 631 632 void ProcInterface::set_symbol(const Symbol &symbol) { 633 CHECK(!type_); 634 symbol_ = &symbol; 635 } 636 void ProcInterface::set_type(const DeclTypeSpec &type) { 637 CHECK(!symbol_); 638 type_ = &type; 639 } 640 } // namespace Fortran::semantics 641