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