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