164ab3302SCarolineConcatto //===-- lib/Semantics/type.cpp --------------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #include "flang/Semantics/type.h"
10f862d858Speter klausler #include "check-declarations.h"
116aa3591eSpeter klausler #include "compute-offsets.h"
1264ab3302SCarolineConcatto #include "flang/Evaluate/fold.h"
13e9be1e7dSPeter Steinfeld #include "flang/Evaluate/tools.h"
1464ab3302SCarolineConcatto #include "flang/Parser/characters.h"
159e7eef99SPeter Klausler #include "flang/Parser/parse-tree-visitor.h"
1664ab3302SCarolineConcatto #include "flang/Semantics/scope.h"
1764ab3302SCarolineConcatto #include "flang/Semantics/symbol.h"
1864ab3302SCarolineConcatto #include "flang/Semantics/tools.h"
198670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h"
2064ab3302SCarolineConcatto 
2164ab3302SCarolineConcatto namespace Fortran::semantics {
2264ab3302SCarolineConcatto 
DerivedTypeSpec(SourceName name,const Symbol & typeSymbol)2364ab3302SCarolineConcatto DerivedTypeSpec::DerivedTypeSpec(SourceName name, const Symbol &typeSymbol)
2464ab3302SCarolineConcatto     : name_{name}, typeSymbol_{typeSymbol} {
2564ab3302SCarolineConcatto   CHECK(typeSymbol.has<DerivedTypeDetails>());
2664ab3302SCarolineConcatto }
2764ab3302SCarolineConcatto DerivedTypeSpec::DerivedTypeSpec(const DerivedTypeSpec &that) = default;
2864ab3302SCarolineConcatto DerivedTypeSpec::DerivedTypeSpec(DerivedTypeSpec &&that) = default;
2964ab3302SCarolineConcatto 
set_scope(const Scope & scope)3064ab3302SCarolineConcatto void DerivedTypeSpec::set_scope(const Scope &scope) {
3164ab3302SCarolineConcatto   CHECK(!scope_);
3264ab3302SCarolineConcatto   ReplaceScope(scope);
3364ab3302SCarolineConcatto }
ReplaceScope(const Scope & scope)3464ab3302SCarolineConcatto void DerivedTypeSpec::ReplaceScope(const Scope &scope) {
3564ab3302SCarolineConcatto   CHECK(scope.IsDerivedType());
3664ab3302SCarolineConcatto   scope_ = &scope;
3764ab3302SCarolineConcatto }
3864ab3302SCarolineConcatto 
AddRawParamValue(const std::optional<parser::Keyword> & keyword,ParamValue && value)3964ab3302SCarolineConcatto void DerivedTypeSpec::AddRawParamValue(
4064ab3302SCarolineConcatto     const std::optional<parser::Keyword> &keyword, ParamValue &&value) {
4164ab3302SCarolineConcatto   CHECK(parameters_.empty());
4264ab3302SCarolineConcatto   rawParameters_.emplace_back(keyword ? &*keyword : nullptr, std::move(value));
4364ab3302SCarolineConcatto }
4464ab3302SCarolineConcatto 
CookParameters(evaluate::FoldingContext & foldingContext)4564ab3302SCarolineConcatto void DerivedTypeSpec::CookParameters(evaluate::FoldingContext &foldingContext) {
4664ab3302SCarolineConcatto   if (cooked_) {
4764ab3302SCarolineConcatto     return;
4864ab3302SCarolineConcatto   }
4964ab3302SCarolineConcatto   cooked_ = true;
5064ab3302SCarolineConcatto   auto &messages{foldingContext.messages()};
5164ab3302SCarolineConcatto   if (IsForwardReferenced()) {
5264ab3302SCarolineConcatto     messages.Say(typeSymbol_.name(),
5364ab3302SCarolineConcatto         "Derived type '%s' was used but never defined"_err_en_US,
5464ab3302SCarolineConcatto         typeSymbol_.name());
5564ab3302SCarolineConcatto     return;
5664ab3302SCarolineConcatto   }
5764ab3302SCarolineConcatto 
5864ab3302SCarolineConcatto   // Parameters of the most deeply nested "base class" come first when the
5964ab3302SCarolineConcatto   // derived type is an extension.
6064ab3302SCarolineConcatto   auto parameterNames{OrderParameterNames(typeSymbol_)};
6164ab3302SCarolineConcatto   auto parameterDecls{OrderParameterDeclarations(typeSymbol_)};
6264ab3302SCarolineConcatto   auto nextNameIter{parameterNames.begin()};
6364ab3302SCarolineConcatto   RawParameters raw{std::move(rawParameters_)};
6464ab3302SCarolineConcatto   for (auto &[maybeKeyword, value] : raw) {
6564ab3302SCarolineConcatto     SourceName name;
6664ab3302SCarolineConcatto     common::TypeParamAttr attr{common::TypeParamAttr::Kind};
6764ab3302SCarolineConcatto     if (maybeKeyword) {
6864ab3302SCarolineConcatto       name = maybeKeyword->v.source;
6964ab3302SCarolineConcatto       auto it{std::find_if(parameterDecls.begin(), parameterDecls.end(),
7064ab3302SCarolineConcatto           [&](const Symbol &symbol) { return symbol.name() == name; })};
7164ab3302SCarolineConcatto       if (it == parameterDecls.end()) {
7264ab3302SCarolineConcatto         messages.Say(name,
7364ab3302SCarolineConcatto             "'%s' is not the name of a parameter for derived type '%s'"_err_en_US,
7464ab3302SCarolineConcatto             name, typeSymbol_.name());
7564ab3302SCarolineConcatto       } else {
7664ab3302SCarolineConcatto         // Resolve the keyword's symbol
7764ab3302SCarolineConcatto         maybeKeyword->v.symbol = const_cast<Symbol *>(&it->get());
7864ab3302SCarolineConcatto         attr = it->get().get<TypeParamDetails>().attr();
7964ab3302SCarolineConcatto       }
8064ab3302SCarolineConcatto     } else if (nextNameIter != parameterNames.end()) {
8164ab3302SCarolineConcatto       name = *nextNameIter++;
8264ab3302SCarolineConcatto       auto it{std::find_if(parameterDecls.begin(), parameterDecls.end(),
8364ab3302SCarolineConcatto           [&](const Symbol &symbol) { return symbol.name() == name; })};
84b6f1bad6SPete Steinfeld       if (it == parameterDecls.end()) {
85b6f1bad6SPete Steinfeld         break;
86b6f1bad6SPete Steinfeld       }
8764ab3302SCarolineConcatto       attr = it->get().get<TypeParamDetails>().attr();
8864ab3302SCarolineConcatto     } else {
8964ab3302SCarolineConcatto       messages.Say(name_,
9064ab3302SCarolineConcatto           "Too many type parameters given for derived type '%s'"_err_en_US,
9164ab3302SCarolineConcatto           typeSymbol_.name());
9264ab3302SCarolineConcatto       break;
9364ab3302SCarolineConcatto     }
9464ab3302SCarolineConcatto     if (FindParameter(name)) {
9564ab3302SCarolineConcatto       messages.Say(name_,
9664ab3302SCarolineConcatto           "Multiple values given for type parameter '%s'"_err_en_US, name);
9764ab3302SCarolineConcatto     } else {
9864ab3302SCarolineConcatto       value.set_attr(attr);
9964ab3302SCarolineConcatto       AddParamValue(name, std::move(value));
10064ab3302SCarolineConcatto     }
10164ab3302SCarolineConcatto   }
10264ab3302SCarolineConcatto }
10364ab3302SCarolineConcatto 
EvaluateParameters(SemanticsContext & context)104627e9007STim Keith void DerivedTypeSpec::EvaluateParameters(SemanticsContext &context) {
105627e9007STim Keith   evaluate::FoldingContext &foldingContext{context.foldingContext()};
10664ab3302SCarolineConcatto   CookParameters(foldingContext);
10764ab3302SCarolineConcatto   if (evaluated_) {
10864ab3302SCarolineConcatto     return;
10964ab3302SCarolineConcatto   }
11064ab3302SCarolineConcatto   evaluated_ = true;
11164ab3302SCarolineConcatto   auto &messages{foldingContext.messages()};
11264ab3302SCarolineConcatto 
11364ab3302SCarolineConcatto   // Fold the explicit type parameter value expressions first.  Do not
11464ab3302SCarolineConcatto   // fold them within the scope of the derived type being instantiated;
11564ab3302SCarolineConcatto   // these expressions cannot use its type parameters.  Convert the values
11664ab3302SCarolineConcatto   // of the expressions to the declared types of the type parameters.
11764ab3302SCarolineConcatto   auto parameterDecls{OrderParameterDeclarations(typeSymbol_)};
11864ab3302SCarolineConcatto   for (const Symbol &symbol : parameterDecls) {
11964ab3302SCarolineConcatto     const SourceName &name{symbol.name()};
12064ab3302SCarolineConcatto     if (ParamValue * paramValue{FindParameter(name)}) {
12164ab3302SCarolineConcatto       if (const MaybeIntExpr & expr{paramValue->GetExplicit()}) {
12264ab3302SCarolineConcatto         if (auto converted{evaluate::ConvertToType(symbol, SomeExpr{*expr})}) {
12364ab3302SCarolineConcatto           SomeExpr folded{
12464ab3302SCarolineConcatto               evaluate::Fold(foldingContext, std::move(*converted))};
12564ab3302SCarolineConcatto           if (auto *intExpr{std::get_if<SomeIntExpr>(&folded.u)}) {
12664ab3302SCarolineConcatto             paramValue->SetExplicit(std::move(*intExpr));
12764ab3302SCarolineConcatto             continue;
12864ab3302SCarolineConcatto           }
12964ab3302SCarolineConcatto         }
130627e9007STim Keith         if (!context.HasError(symbol)) {
13164ab3302SCarolineConcatto           evaluate::SayWithDeclaration(messages, symbol,
13238095549SPete Steinfeld               "Value of type parameter '%s' (%s) is not convertible to its"
13338095549SPete Steinfeld               " type"_err_en_US,
13464ab3302SCarolineConcatto               name, expr->AsFortran());
13564ab3302SCarolineConcatto         }
13664ab3302SCarolineConcatto       }
13764ab3302SCarolineConcatto     }
13838095549SPete Steinfeld   }
13964ab3302SCarolineConcatto 
14064ab3302SCarolineConcatto   // Default initialization expressions for the derived type's parameters
14164ab3302SCarolineConcatto   // may reference other parameters so long as the declaration precedes the
14264ab3302SCarolineConcatto   // use in the expression (10.1.12).  This is not necessarily the same
14364ab3302SCarolineConcatto   // order as "type parameter order" (7.5.3.2).
14464ab3302SCarolineConcatto   // Type parameter default value expressions are folded in declaration order
14564ab3302SCarolineConcatto   // within the scope of the derived type so that the values of earlier type
14664ab3302SCarolineConcatto   // parameters are available for use in the default initialization
14764ab3302SCarolineConcatto   // expressions of later parameters.
14864ab3302SCarolineConcatto   auto restorer{foldingContext.WithPDTInstance(*this)};
14964ab3302SCarolineConcatto   for (const Symbol &symbol : parameterDecls) {
15064ab3302SCarolineConcatto     const SourceName &name{symbol.name()};
15164ab3302SCarolineConcatto     if (!FindParameter(name)) {
15264ab3302SCarolineConcatto       const TypeParamDetails &details{symbol.get<TypeParamDetails>()};
15364ab3302SCarolineConcatto       if (details.init()) {
154641ede93Speter klausler         auto expr{evaluate::Fold(foldingContext, SomeExpr{*details.init()})};
155641ede93Speter klausler         AddParamValue(name,
156641ede93Speter klausler             ParamValue{
157641ede93Speter klausler                 std::move(std::get<SomeIntExpr>(expr.u)), details.attr()});
158627e9007STim Keith       } else if (!context.HasError(symbol)) {
15964ab3302SCarolineConcatto         messages.Say(name_,
16064ab3302SCarolineConcatto             "Type parameter '%s' lacks a value and has no default"_err_en_US,
16164ab3302SCarolineConcatto             name);
16264ab3302SCarolineConcatto       }
16364ab3302SCarolineConcatto     }
16464ab3302SCarolineConcatto   }
16564ab3302SCarolineConcatto }
16664ab3302SCarolineConcatto 
AddParamValue(SourceName name,ParamValue && value)16764ab3302SCarolineConcatto void DerivedTypeSpec::AddParamValue(SourceName name, ParamValue &&value) {
16864ab3302SCarolineConcatto   CHECK(cooked_);
16964ab3302SCarolineConcatto   auto pair{parameters_.insert(std::make_pair(name, std::move(value)))};
17064ab3302SCarolineConcatto   CHECK(pair.second); // name was not already present
17164ab3302SCarolineConcatto }
17264ab3302SCarolineConcatto 
MightBeParameterized() const17364ab3302SCarolineConcatto bool DerivedTypeSpec::MightBeParameterized() const {
17464ab3302SCarolineConcatto   return !cooked_ || !parameters_.empty();
17564ab3302SCarolineConcatto }
17664ab3302SCarolineConcatto 
IsForwardReferenced() const17764ab3302SCarolineConcatto bool DerivedTypeSpec::IsForwardReferenced() const {
17864ab3302SCarolineConcatto   return typeSymbol_.get<DerivedTypeDetails>().isForwardReferenced();
17964ab3302SCarolineConcatto }
18064ab3302SCarolineConcatto 
HasDefaultInitialization(bool ignoreAllocatable) const181c4f67ea1SPeter Klausler bool DerivedTypeSpec::HasDefaultInitialization(bool ignoreAllocatable) const {
1824171f80dSpeter klausler   DirectComponentIterator components{*this};
183c4f67ea1SPeter Klausler   return bool{std::find_if(
184c4f67ea1SPeter Klausler       components.begin(), components.end(), [&](const Symbol &component) {
185c4f67ea1SPeter Klausler         return IsInitialized(component, true, ignoreAllocatable);
186c4f67ea1SPeter Klausler       })};
18764ab3302SCarolineConcatto }
18864ab3302SCarolineConcatto 
HasDestruction() const189a48e4168Speter klausler bool DerivedTypeSpec::HasDestruction() const {
190a48e4168Speter klausler   if (!typeSymbol().get<DerivedTypeDetails>().finals().empty()) {
191a48e4168Speter klausler     return true;
192a48e4168Speter klausler   }
193a48e4168Speter klausler   DirectComponentIterator components{*this};
194a48e4168Speter klausler   return bool{std::find_if(
195a48e4168Speter klausler       components.begin(), components.end(), [&](const Symbol &component) {
196a48e4168Speter klausler         return IsDestructible(component, &typeSymbol());
197a48e4168Speter klausler       })};
198a48e4168Speter klausler }
199a48e4168Speter klausler 
FindParameter(SourceName target)20064ab3302SCarolineConcatto ParamValue *DerivedTypeSpec::FindParameter(SourceName target) {
20164ab3302SCarolineConcatto   return const_cast<ParamValue *>(
20264ab3302SCarolineConcatto       const_cast<const DerivedTypeSpec *>(this)->FindParameter(target));
20364ab3302SCarolineConcatto }
20464ab3302SCarolineConcatto 
Match(const DerivedTypeSpec & that) const205142cbd50SPeter Klausler bool DerivedTypeSpec::Match(const DerivedTypeSpec &that) const {
206142cbd50SPeter Klausler   if (&typeSymbol_ != &that.typeSymbol_) {
207142cbd50SPeter Klausler     return false;
208142cbd50SPeter Klausler   }
209142cbd50SPeter Klausler   for (const auto &pair : parameters_) {
210142cbd50SPeter Klausler     const Symbol *tpSym{scope_ ? scope_->FindSymbol(pair.first) : nullptr};
211142cbd50SPeter Klausler     const auto *tpDetails{
212142cbd50SPeter Klausler         tpSym ? tpSym->detailsIf<TypeParamDetails>() : nullptr};
213142cbd50SPeter Klausler     if (!tpDetails) {
214142cbd50SPeter Klausler       return false;
215142cbd50SPeter Klausler     }
216142cbd50SPeter Klausler     if (tpDetails->attr() != common::TypeParamAttr::Kind) {
217142cbd50SPeter Klausler       continue;
218142cbd50SPeter Klausler     }
219142cbd50SPeter Klausler     const ParamValue &value{pair.second};
220142cbd50SPeter Klausler     auto iter{that.parameters_.find(pair.first)};
221142cbd50SPeter Klausler     if (iter == that.parameters_.end() || iter->second != value) {
222142cbd50SPeter Klausler       return false;
223142cbd50SPeter Klausler     }
224142cbd50SPeter Klausler   }
225142cbd50SPeter Klausler   return true;
226142cbd50SPeter Klausler }
227142cbd50SPeter Klausler 
2289623003eSTim Keith class InstantiateHelper {
2299623003eSTim Keith public:
InstantiateHelper(Scope & scope)2305091671cSpeter klausler   InstantiateHelper(Scope &scope) : scope_{scope} {}
2319623003eSTim Keith   // Instantiate components from fromScope into scope_
2329623003eSTim Keith   void InstantiateComponents(const Scope &);
2339623003eSTim Keith 
2349623003eSTim Keith private:
context() const2355091671cSpeter klausler   SemanticsContext &context() const { return scope_.context(); }
foldingContext()2369623003eSTim Keith   evaluate::FoldingContext &foldingContext() {
2375091671cSpeter klausler     return context().foldingContext();
2389623003eSTim Keith   }
Fold(A && expr)239803f1e46Speter klausler   template <typename A> A Fold(A &&expr) {
2409623003eSTim Keith     return evaluate::Fold(foldingContext(), std::move(expr));
2419623003eSTim Keith   }
2429623003eSTim Keith   void InstantiateComponent(const Symbol &);
2439623003eSTim Keith   const DeclTypeSpec *InstantiateType(const Symbol &);
24452cc9df1SPeter Steinfeld   const DeclTypeSpec &InstantiateIntrinsicType(
24552cc9df1SPeter Steinfeld       SourceName, const DeclTypeSpec &);
2469623003eSTim Keith   DerivedTypeSpec CreateDerivedTypeSpec(const DerivedTypeSpec &, bool);
2479623003eSTim Keith 
2489623003eSTim Keith   Scope &scope_;
2499623003eSTim Keith };
2509623003eSTim Keith 
PlumbPDTInstantiationDepth(const Scope * scope)2515091671cSpeter klausler static int PlumbPDTInstantiationDepth(const Scope *scope) {
2525091671cSpeter klausler   int depth{0};
2535091671cSpeter klausler   while (scope->IsParameterizedDerivedTypeInstantiation()) {
2545091671cSpeter klausler     ++depth;
2555091671cSpeter klausler     scope = &scope->parent();
2565091671cSpeter klausler   }
2575091671cSpeter klausler   return depth;
2585091671cSpeter klausler }
2595091671cSpeter klausler 
260a48e4168Speter klausler // Completes component derived type instantiation and initializer folding
261a48e4168Speter klausler // for a non-parameterized derived type Scope.
InstantiateNonPDTScope(Scope & typeScope,Scope & containingScope)262a48e4168Speter klausler static void InstantiateNonPDTScope(Scope &typeScope, Scope &containingScope) {
2635091671cSpeter klausler   auto &context{containingScope.context()};
26464ab3302SCarolineConcatto   auto &foldingContext{context.foldingContext()};
2659623003eSTim Keith   for (auto &pair : typeScope) {
2669623003eSTim Keith     Symbol &symbol{*pair.second};
2679623003eSTim Keith     if (DeclTypeSpec * type{symbol.GetType()}) {
2689623003eSTim Keith       if (DerivedTypeSpec * derived{type->AsDerived()}) {
26964ab3302SCarolineConcatto         if (!(derived->IsForwardReferenced() &&
27064ab3302SCarolineConcatto                 IsAllocatableOrPointer(symbol))) {
2715091671cSpeter klausler           derived->Instantiate(containingScope);
27264ab3302SCarolineConcatto         }
27364ab3302SCarolineConcatto       }
27464ab3302SCarolineConcatto     }
275641ede93Speter klausler     if (!IsPointer(symbol)) {
276641ede93Speter klausler       if (auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
277641ede93Speter klausler         if (MaybeExpr & init{object->init()}) {
278641ede93Speter klausler           auto restorer{foldingContext.messages().SetLocation(symbol.name())};
279641ede93Speter klausler           init = evaluate::NonPointerInitializationExpr(
280641ede93Speter klausler               symbol, std::move(*init), foldingContext);
281641ede93Speter klausler         }
282641ede93Speter klausler       }
283641ede93Speter klausler     }
28464ab3302SCarolineConcatto   }
285a48e4168Speter klausler   ComputeOffsets(context, typeScope);
286a48e4168Speter klausler }
287a48e4168Speter klausler 
Instantiate(Scope & containingScope)288a48e4168Speter klausler void DerivedTypeSpec::Instantiate(Scope &containingScope) {
289a48e4168Speter klausler   if (instantiated_) {
290a48e4168Speter klausler     return;
291a48e4168Speter klausler   }
292a48e4168Speter klausler   instantiated_ = true;
293a48e4168Speter klausler   auto &context{containingScope.context()};
294a48e4168Speter klausler   auto &foldingContext{context.foldingContext()};
295a48e4168Speter klausler   if (IsForwardReferenced()) {
296a48e4168Speter klausler     foldingContext.messages().Say(typeSymbol_.name(),
297a48e4168Speter klausler         "The derived type '%s' was forward-referenced but not defined"_err_en_US,
298a48e4168Speter klausler         typeSymbol_.name());
299a48e4168Speter klausler     context.SetError(typeSymbol_);
300a48e4168Speter klausler     return;
301a48e4168Speter klausler   }
302a48e4168Speter klausler   EvaluateParameters(context);
303a48e4168Speter klausler   const Scope &typeScope{DEREF(typeSymbol_.scope())};
304a48e4168Speter klausler   if (!MightBeParameterized()) {
305a48e4168Speter klausler     scope_ = &typeScope;
306a48e4168Speter klausler     if (typeScope.derivedTypeSpec()) {
307a48e4168Speter klausler       CHECK(*this == *typeScope.derivedTypeSpec());
308a48e4168Speter klausler     } else {
309a48e4168Speter klausler       Scope &mutableTypeScope{const_cast<Scope &>(typeScope)};
310a48e4168Speter klausler       mutableTypeScope.set_derivedTypeSpec(*this);
311a48e4168Speter klausler       InstantiateNonPDTScope(mutableTypeScope, containingScope);
312a48e4168Speter klausler     }
31364ab3302SCarolineConcatto     return;
31464ab3302SCarolineConcatto   }
3155091671cSpeter klausler   // New PDT instantiation.  Create a new scope and populate it
3165091671cSpeter klausler   // with components that have been specialized for this set of
3175091671cSpeter klausler   // parameters.
31864ab3302SCarolineConcatto   Scope &newScope{containingScope.MakeScope(Scope::Kind::DerivedType)};
31964ab3302SCarolineConcatto   newScope.set_derivedTypeSpec(*this);
32064ab3302SCarolineConcatto   ReplaceScope(newScope);
321641ede93Speter klausler   auto restorer{foldingContext.WithPDTInstance(*this)};
322641ede93Speter klausler   std::string desc{typeSymbol_.name().ToString()};
323641ede93Speter klausler   char sep{'('};
32464ab3302SCarolineConcatto   for (const Symbol &symbol : OrderParameterDeclarations(typeSymbol_)) {
32564ab3302SCarolineConcatto     const SourceName &name{symbol.name()};
32664ab3302SCarolineConcatto     if (typeScope.find(symbol.name()) != typeScope.end()) {
32764ab3302SCarolineConcatto       // This type parameter belongs to the derived type itself, not to
32864ab3302SCarolineConcatto       // one of its ancestors.  Put the type parameter expression value
32964ab3302SCarolineConcatto       // into the new scope as the initialization value for the parameter.
33064ab3302SCarolineConcatto       if (ParamValue * paramValue{FindParameter(name)}) {
33164ab3302SCarolineConcatto         const TypeParamDetails &details{symbol.get<TypeParamDetails>()};
33264ab3302SCarolineConcatto         paramValue->set_attr(details.attr());
33364ab3302SCarolineConcatto         if (MaybeIntExpr expr{paramValue->GetExplicit()}) {
334641ede93Speter klausler           if (auto folded{evaluate::NonPointerInitializationExpr(symbol,
335641ede93Speter klausler                   SomeExpr{std::move(*expr)}, foldingContext, &newScope)}) {
336641ede93Speter klausler             desc += sep;
337641ede93Speter klausler             desc += name.ToString();
338641ede93Speter klausler             desc += '=';
339641ede93Speter klausler             desc += folded->AsFortran();
340641ede93Speter klausler             sep = ',';
34164ab3302SCarolineConcatto             TypeParamDetails instanceDetails{details.attr()};
34264ab3302SCarolineConcatto             if (const DeclTypeSpec * type{details.type()}) {
34364ab3302SCarolineConcatto               instanceDetails.set_type(*type);
34464ab3302SCarolineConcatto             }
345641ede93Speter klausler             instanceDetails.set_init(
346641ede93Speter klausler                 std::move(DEREF(evaluate::UnwrapExpr<SomeIntExpr>(*folded))));
34764ab3302SCarolineConcatto             newScope.try_emplace(name, std::move(instanceDetails));
34864ab3302SCarolineConcatto           }
34964ab3302SCarolineConcatto         }
35064ab3302SCarolineConcatto       }
35164ab3302SCarolineConcatto     }
352641ede93Speter klausler   }
353641ede93Speter klausler   parser::Message *contextMessage{nullptr};
354641ede93Speter klausler   if (sep != '(') {
355641ede93Speter klausler     desc += ')';
356641ede93Speter klausler     contextMessage = new parser::Message{foldingContext.messages().at(),
357641ede93Speter klausler         "instantiation of parameterized derived type '%s'"_en_US, desc};
358641ede93Speter klausler     if (auto outer{containingScope.instantiationContext()}) {
359641ede93Speter klausler       contextMessage->SetContext(outer.get());
360641ede93Speter klausler     }
361641ede93Speter klausler     newScope.set_instantiationContext(contextMessage);
362641ede93Speter klausler   }
36364ab3302SCarolineConcatto   // Instantiate every non-parameter symbol from the original derived
36464ab3302SCarolineConcatto   // type's scope into the new instance.
36564ab3302SCarolineConcatto   newScope.AddSourceRange(typeScope.sourceRange());
366641ede93Speter klausler   auto restorer2{foldingContext.messages().SetContext(contextMessage)};
3675091671cSpeter klausler   if (PlumbPDTInstantiationDepth(&containingScope) > 100) {
3685091671cSpeter klausler     foldingContext.messages().Say(
3695091671cSpeter klausler         "Too many recursive parameterized derived type instantiations"_err_en_US);
3705091671cSpeter klausler   } else {
3715091671cSpeter klausler     InstantiateHelper{newScope}.InstantiateComponents(typeScope);
3725091671cSpeter klausler   }
37364ab3302SCarolineConcatto }
3749623003eSTim Keith 
InstantiateComponents(const Scope & fromScope)3759623003eSTim Keith void InstantiateHelper::InstantiateComponents(const Scope &fromScope) {
37603095bd9SPeter Klausler   // Instantiate symbols in declaration order; this ensures that
37703095bd9SPeter Klausler   // parent components and type parameters of ancestor types exist
37803095bd9SPeter Klausler   // by the time that they're needed.
37903095bd9SPeter Klausler   for (SymbolRef ref : fromScope.GetSymbols()) {
38003095bd9SPeter Klausler     InstantiateComponent(*ref);
3819623003eSTim Keith   }
3825091671cSpeter klausler   ComputeOffsets(context(), scope_);
3839623003eSTim Keith }
3849623003eSTim Keith 
3859e7eef99SPeter Klausler // Walks a parsed expression to prepare it for (re)analysis;
3869e7eef99SPeter Klausler // clears out the typedExpr analysis results and re-resolves
3879e7eef99SPeter Klausler // symbol table pointers of type parameters.
3889e7eef99SPeter Klausler class ComponentInitResetHelper {
3899e7eef99SPeter Klausler public:
ComponentInitResetHelper(Scope & scope)3909e7eef99SPeter Klausler   explicit ComponentInitResetHelper(Scope &scope) : scope_{scope} {}
3919e7eef99SPeter Klausler 
Pre(const A &)3929e7eef99SPeter Klausler   template <typename A> bool Pre(const A &) { return true; }
3939e7eef99SPeter Klausler 
Post(const A & x)3949e7eef99SPeter Klausler   template <typename A> void Post(const A &x) {
3959e7eef99SPeter Klausler     if constexpr (parser::HasTypedExpr<A>()) {
3969e7eef99SPeter Klausler       x.typedExpr.Reset();
3979e7eef99SPeter Klausler     }
3989e7eef99SPeter Klausler   }
3999e7eef99SPeter Klausler 
Post(const parser::Name & name)4009e7eef99SPeter Klausler   void Post(const parser::Name &name) {
4019e7eef99SPeter Klausler     if (name.symbol && name.symbol->has<TypeParamDetails>()) {
40203095bd9SPeter Klausler       name.symbol = scope_.FindComponent(name.source);
4039e7eef99SPeter Klausler     }
4049e7eef99SPeter Klausler   }
4059e7eef99SPeter Klausler 
4069e7eef99SPeter Klausler private:
4079e7eef99SPeter Klausler   Scope &scope_;
4089e7eef99SPeter Klausler };
4099e7eef99SPeter Klausler 
InstantiateComponent(const Symbol & oldSymbol)4109623003eSTim Keith void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {
4119623003eSTim Keith   auto pair{scope_.try_emplace(
4129623003eSTim Keith       oldSymbol.name(), oldSymbol.attrs(), common::Clone(oldSymbol.details()))};
4139623003eSTim Keith   Symbol &newSymbol{*pair.first->second};
4149623003eSTim Keith   if (!pair.second) {
4159623003eSTim Keith     // Symbol was already present in the scope, which can only happen
4169623003eSTim Keith     // in the case of type parameters.
4179623003eSTim Keith     CHECK(oldSymbol.has<TypeParamDetails>());
4189623003eSTim Keith     return;
4199623003eSTim Keith   }
4209623003eSTim Keith   newSymbol.flags() = oldSymbol.flags();
4219623003eSTim Keith   if (auto *details{newSymbol.detailsIf<ObjectEntityDetails>()}) {
4229623003eSTim Keith     if (const DeclTypeSpec * newType{InstantiateType(newSymbol)}) {
4239623003eSTim Keith       details->ReplaceType(*newType);
4249623003eSTim Keith     }
4259623003eSTim Keith     for (ShapeSpec &dim : details->shape()) {
4269623003eSTim Keith       if (dim.lbound().isExplicit()) {
4279623003eSTim Keith         dim.lbound().SetExplicit(Fold(std::move(dim.lbound().GetExplicit())));
4289623003eSTim Keith       }
4299623003eSTim Keith       if (dim.ubound().isExplicit()) {
4309623003eSTim Keith         dim.ubound().SetExplicit(Fold(std::move(dim.ubound().GetExplicit())));
4319623003eSTim Keith       }
4329623003eSTim Keith     }
4339623003eSTim Keith     for (ShapeSpec &dim : details->coshape()) {
4349623003eSTim Keith       if (dim.lbound().isExplicit()) {
4359623003eSTim Keith         dim.lbound().SetExplicit(Fold(std::move(dim.lbound().GetExplicit())));
4369623003eSTim Keith       }
4379623003eSTim Keith       if (dim.ubound().isExplicit()) {
4389623003eSTim Keith         dim.ubound().SetExplicit(Fold(std::move(dim.ubound().GetExplicit())));
4399623003eSTim Keith       }
4409623003eSTim Keith     }
4419e7eef99SPeter Klausler     if (const auto *parsedExpr{details->unanalyzedPDTComponentInit()}) {
4429e7eef99SPeter Klausler       // Analyze the parsed expression in this PDT instantiation context.
4439e7eef99SPeter Klausler       ComponentInitResetHelper resetter{scope_};
4449e7eef99SPeter Klausler       parser::Walk(*parsedExpr, resetter);
4459e7eef99SPeter Klausler       auto restorer{foldingContext().messages().SetLocation(newSymbol.name())};
4469e7eef99SPeter Klausler       details->set_init(evaluate::Fold(
4479e7eef99SPeter Klausler           foldingContext(), AnalyzeExpr(context(), *parsedExpr)));
4489e7eef99SPeter Klausler       details->set_unanalyzedPDTComponentInit(nullptr);
4499e7eef99SPeter Klausler       // Remove analysis results to prevent unparsing or other use of
4509e7eef99SPeter Klausler       // instantiation-specific expressions.
4519e7eef99SPeter Klausler       parser::Walk(*parsedExpr, resetter);
4529e7eef99SPeter Klausler     }
453641ede93Speter klausler     if (MaybeExpr & init{details->init()}) {
454641ede93Speter klausler       // Non-pointer components with default initializers are
455641ede93Speter klausler       // processed now so that those default initializers can be used
456641ede93Speter klausler       // in PARAMETER structure constructors.
457641ede93Speter klausler       auto restorer{foldingContext().messages().SetLocation(newSymbol.name())};
458641ede93Speter klausler       init = IsPointer(newSymbol)
459803f1e46Speter klausler           ? Fold(std::move(*init))
460641ede93Speter klausler           : evaluate::NonPointerInitializationExpr(
461641ede93Speter klausler                 newSymbol, std::move(*init), foldingContext());
462641ede93Speter klausler     }
463bef63dc8SPeter Steinfeld   } else if (auto *procDetails{newSymbol.detailsIf<ProcEntityDetails>()}) {
464bef63dc8SPeter Steinfeld     // We have a procedure pointer.  Instantiate its return type
465bef63dc8SPeter Steinfeld     if (const DeclTypeSpec * returnType{InstantiateType(newSymbol)}) {
466bef63dc8SPeter Steinfeld       ProcInterface &interface{procDetails->interface()};
467bef63dc8SPeter Steinfeld       if (!interface.symbol()) {
468bef63dc8SPeter Steinfeld         // Don't change the type for interfaces based on symbols
469bef63dc8SPeter Steinfeld         interface.set_type(*returnType);
470bef63dc8SPeter Steinfeld       }
471bef63dc8SPeter Steinfeld     }
4729623003eSTim Keith   }
4739623003eSTim Keith }
4749623003eSTim Keith 
InstantiateType(const Symbol & symbol)4759623003eSTim Keith const DeclTypeSpec *InstantiateHelper::InstantiateType(const Symbol &symbol) {
4769623003eSTim Keith   const DeclTypeSpec *type{symbol.GetType()};
4779623003eSTim Keith   if (!type) {
4789623003eSTim Keith     return nullptr; // error has occurred
4799623003eSTim Keith   } else if (const DerivedTypeSpec * spec{type->AsDerived()}) {
4809623003eSTim Keith     return &FindOrInstantiateDerivedType(scope_,
4819623003eSTim Keith         CreateDerivedTypeSpec(*spec, symbol.test(Symbol::Flag::ParentComp)),
4825091671cSpeter klausler         type->category());
4834ced7a48STim Keith   } else if (type->AsIntrinsic()) {
48452cc9df1SPeter Steinfeld     return &InstantiateIntrinsicType(symbol.name(), *type);
4859623003eSTim Keith   } else if (type->category() == DeclTypeSpec::ClassStar) {
4869623003eSTim Keith     return type;
4879623003eSTim Keith   } else {
4889623003eSTim Keith     common::die("InstantiateType: %s", type->AsFortran().c_str());
4899623003eSTim Keith   }
4909623003eSTim Keith }
4919623003eSTim Keith 
492b8e8f62dSJean Perier /// Fold explicit length parameters of character components when the explicit
493b8e8f62dSJean Perier /// expression is a constant expression (if it only depends on KIND parameters).
494b8e8f62dSJean Perier /// Do not fold `character(len=pdt_length)`, even if the length parameter is
495b8e8f62dSJean Perier /// constant in the pdt instantiation, in order to avoid losing the information
496b8e8f62dSJean Perier /// that the character component is automatic (and must be a descriptor).
FoldCharacterLength(evaluate::FoldingContext & foldingContext,const CharacterTypeSpec & characterSpec)497b8e8f62dSJean Perier static ParamValue FoldCharacterLength(evaluate::FoldingContext &foldingContext,
498b8e8f62dSJean Perier     const CharacterTypeSpec &characterSpec) {
499b8e8f62dSJean Perier   if (const auto &len{characterSpec.length().GetExplicit()}) {
500b8e8f62dSJean Perier     if (evaluate::IsConstantExpr(*len)) {
501b8e8f62dSJean Perier       return ParamValue{evaluate::Fold(foldingContext, common::Clone(*len)),
502b8e8f62dSJean Perier           common::TypeParamAttr::Len};
503b8e8f62dSJean Perier     }
504b8e8f62dSJean Perier   }
505b8e8f62dSJean Perier   return characterSpec.length();
506b8e8f62dSJean Perier }
507b8e8f62dSJean Perier 
5089623003eSTim Keith // Apply type parameter values to an intrinsic type spec.
InstantiateIntrinsicType(SourceName symbolName,const DeclTypeSpec & spec)5099623003eSTim Keith const DeclTypeSpec &InstantiateHelper::InstantiateIntrinsicType(
51052cc9df1SPeter Steinfeld     SourceName symbolName, const DeclTypeSpec &spec) {
5119623003eSTim Keith   const IntrinsicTypeSpec &intrinsic{DEREF(spec.AsIntrinsic())};
512b8e8f62dSJean Perier   if (spec.category() != DeclTypeSpec::Character &&
513b8e8f62dSJean Perier       evaluate::IsActuallyConstant(intrinsic.kind())) {
5149623003eSTim Keith     return spec; // KIND is already a known constant
5159623003eSTim Keith   }
5169623003eSTim Keith   // The expression was not originally constant, but now it must be so
5179623003eSTim Keith   // in the context of a parameterized derived type instantiation.
5189623003eSTim Keith   KindExpr copy{Fold(common::Clone(intrinsic.kind()))};
5195091671cSpeter klausler   int kind{context().GetDefaultKind(intrinsic.category())};
5209623003eSTim Keith   if (auto value{evaluate::ToInt64(copy)}) {
521*23c2bedfSPeter Klausler     if (foldingContext().targetCharacteristics().IsTypeEnabled(
522*23c2bedfSPeter Klausler             intrinsic.category(), *value)) {
5239623003eSTim Keith       kind = *value;
5249623003eSTim Keith     } else {
52552cc9df1SPeter Steinfeld       foldingContext().messages().Say(symbolName,
5269623003eSTim Keith           "KIND parameter value (%jd) of intrinsic type %s "
5279623003eSTim Keith           "did not resolve to a supported value"_err_en_US,
5289623003eSTim Keith           *value,
5299623003eSTim Keith           parser::ToUpperCaseLetters(EnumToString(intrinsic.category())));
5309623003eSTim Keith     }
5319623003eSTim Keith   }
5329623003eSTim Keith   switch (spec.category()) {
5339623003eSTim Keith   case DeclTypeSpec::Numeric:
5349623003eSTim Keith     return scope_.MakeNumericType(intrinsic.category(), KindExpr{kind});
5359623003eSTim Keith   case DeclTypeSpec::Logical:
5369623003eSTim Keith     return scope_.MakeLogicalType(KindExpr{kind});
5379623003eSTim Keith   case DeclTypeSpec::Character:
5389623003eSTim Keith     return scope_.MakeCharacterType(
539b8e8f62dSJean Perier         FoldCharacterLength(foldingContext(), spec.characterTypeSpec()),
540b8e8f62dSJean Perier         KindExpr{kind});
5419623003eSTim Keith   default:
5429623003eSTim Keith     CRASH_NO_CASE;
5439623003eSTim Keith   }
5449623003eSTim Keith }
5459623003eSTim Keith 
CreateDerivedTypeSpec(const DerivedTypeSpec & spec,bool isParentComp)5469623003eSTim Keith DerivedTypeSpec InstantiateHelper::CreateDerivedTypeSpec(
5479623003eSTim Keith     const DerivedTypeSpec &spec, bool isParentComp) {
5489623003eSTim Keith   DerivedTypeSpec result{spec};
5499623003eSTim Keith   result.CookParameters(foldingContext()); // enables AddParamValue()
5509623003eSTim Keith   if (isParentComp) {
5519623003eSTim Keith     // Forward any explicit type parameter values from the
5529623003eSTim Keith     // derived type spec under instantiation that define type parameters
5539623003eSTim Keith     // of the parent component to the derived type spec of the
5549623003eSTim Keith     // parent component.
5559623003eSTim Keith     const DerivedTypeSpec &instanceSpec{DEREF(foldingContext().pdtInstance())};
5569623003eSTim Keith     for (const auto &[name, value] : instanceSpec.parameters()) {
5579623003eSTim Keith       if (scope_.find(name) == scope_.end()) {
5589623003eSTim Keith         result.AddParamValue(name, ParamValue{value});
5599623003eSTim Keith       }
5609623003eSTim Keith     }
5619623003eSTim Keith   }
5629623003eSTim Keith   return result;
56364ab3302SCarolineConcatto }
56464ab3302SCarolineConcatto 
AsFortran() const56564ab3302SCarolineConcatto std::string DerivedTypeSpec::AsFortran() const {
5668670e499SCaroline Concatto   std::string buf;
5678670e499SCaroline Concatto   llvm::raw_string_ostream ss{buf};
56864ab3302SCarolineConcatto   ss << name_;
56964ab3302SCarolineConcatto   if (!rawParameters_.empty()) {
57064ab3302SCarolineConcatto     CHECK(parameters_.empty());
57164ab3302SCarolineConcatto     ss << '(';
57264ab3302SCarolineConcatto     bool first = true;
57364ab3302SCarolineConcatto     for (const auto &[maybeKeyword, value] : rawParameters_) {
57464ab3302SCarolineConcatto       if (first) {
57564ab3302SCarolineConcatto         first = false;
57664ab3302SCarolineConcatto       } else {
57764ab3302SCarolineConcatto         ss << ',';
57864ab3302SCarolineConcatto       }
57964ab3302SCarolineConcatto       if (maybeKeyword) {
58064ab3302SCarolineConcatto         ss << maybeKeyword->v.source.ToString() << '=';
58164ab3302SCarolineConcatto       }
58264ab3302SCarolineConcatto       ss << value.AsFortran();
58364ab3302SCarolineConcatto     }
58464ab3302SCarolineConcatto     ss << ')';
58564ab3302SCarolineConcatto   } else if (!parameters_.empty()) {
58664ab3302SCarolineConcatto     ss << '(';
58764ab3302SCarolineConcatto     bool first = true;
58864ab3302SCarolineConcatto     for (const auto &[name, value] : parameters_) {
58964ab3302SCarolineConcatto       if (first) {
59064ab3302SCarolineConcatto         first = false;
59164ab3302SCarolineConcatto       } else {
59264ab3302SCarolineConcatto         ss << ',';
59364ab3302SCarolineConcatto       }
59464ab3302SCarolineConcatto       ss << name.ToString() << '=' << value.AsFortran();
59564ab3302SCarolineConcatto     }
59664ab3302SCarolineConcatto     ss << ')';
59764ab3302SCarolineConcatto   }
59864ab3302SCarolineConcatto   return ss.str();
59964ab3302SCarolineConcatto }
60064ab3302SCarolineConcatto 
operator <<(llvm::raw_ostream & o,const DerivedTypeSpec & x)6018670e499SCaroline Concatto llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const DerivedTypeSpec &x) {
60264ab3302SCarolineConcatto   return o << x.AsFortran();
60364ab3302SCarolineConcatto }
60464ab3302SCarolineConcatto 
Bound(common::ConstantSubscript bound)6054ac617f4Speter klausler Bound::Bound(common::ConstantSubscript bound) : expr_{bound} {}
60664ab3302SCarolineConcatto 
operator <<(llvm::raw_ostream & o,const Bound & x)6078670e499SCaroline Concatto llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const Bound &x) {
60844bc97c8SPeter Klausler   if (x.isStar()) {
60964ab3302SCarolineConcatto     o << '*';
61044bc97c8SPeter Klausler   } else if (x.isColon()) {
61164ab3302SCarolineConcatto     o << ':';
61264ab3302SCarolineConcatto   } else if (x.expr_) {
61364ab3302SCarolineConcatto     x.expr_->AsFortran(o);
61464ab3302SCarolineConcatto   } else {
61564ab3302SCarolineConcatto     o << "<no-expr>";
61664ab3302SCarolineConcatto   }
61764ab3302SCarolineConcatto   return o;
61864ab3302SCarolineConcatto }
61964ab3302SCarolineConcatto 
operator <<(llvm::raw_ostream & o,const ShapeSpec & x)6208670e499SCaroline Concatto llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const ShapeSpec &x) {
62144bc97c8SPeter Klausler   if (x.lb_.isStar()) {
62244bc97c8SPeter Klausler     CHECK(x.ub_.isStar());
62364ab3302SCarolineConcatto     o << "..";
62464ab3302SCarolineConcatto   } else {
62544bc97c8SPeter Klausler     if (!x.lb_.isColon()) {
62664ab3302SCarolineConcatto       o << x.lb_;
62764ab3302SCarolineConcatto     }
62864ab3302SCarolineConcatto     o << ':';
62944bc97c8SPeter Klausler     if (!x.ub_.isColon()) {
63064ab3302SCarolineConcatto       o << x.ub_;
63164ab3302SCarolineConcatto     }
63264ab3302SCarolineConcatto   }
63364ab3302SCarolineConcatto   return o;
63464ab3302SCarolineConcatto }
63564ab3302SCarolineConcatto 
operator <<(llvm::raw_ostream & os,const ArraySpec & arraySpec)6368670e499SCaroline Concatto llvm::raw_ostream &operator<<(
6378670e499SCaroline Concatto     llvm::raw_ostream &os, const ArraySpec &arraySpec) {
63864ab3302SCarolineConcatto   char sep{'('};
63964ab3302SCarolineConcatto   for (auto &shape : arraySpec) {
64064ab3302SCarolineConcatto     os << sep << shape;
64164ab3302SCarolineConcatto     sep = ',';
64264ab3302SCarolineConcatto   }
64364ab3302SCarolineConcatto   if (sep == ',') {
64464ab3302SCarolineConcatto     os << ')';
64564ab3302SCarolineConcatto   }
64664ab3302SCarolineConcatto   return os;
64764ab3302SCarolineConcatto }
64864ab3302SCarolineConcatto 
ParamValue(MaybeIntExpr && expr,common::TypeParamAttr attr)64964ab3302SCarolineConcatto ParamValue::ParamValue(MaybeIntExpr &&expr, common::TypeParamAttr attr)
65064ab3302SCarolineConcatto     : attr_{attr}, expr_{std::move(expr)} {}
ParamValue(SomeIntExpr && expr,common::TypeParamAttr attr)65164ab3302SCarolineConcatto ParamValue::ParamValue(SomeIntExpr &&expr, common::TypeParamAttr attr)
65264ab3302SCarolineConcatto     : attr_{attr}, expr_{std::move(expr)} {}
ParamValue(common::ConstantSubscript value,common::TypeParamAttr attr)65364ab3302SCarolineConcatto ParamValue::ParamValue(
65464ab3302SCarolineConcatto     common::ConstantSubscript value, common::TypeParamAttr attr)
6551f879005STim Keith     : ParamValue(SomeIntExpr{evaluate::Expr<evaluate::SubscriptInteger>{value}},
6561f879005STim Keith           attr) {}
65764ab3302SCarolineConcatto 
SetExplicit(SomeIntExpr && x)65864ab3302SCarolineConcatto void ParamValue::SetExplicit(SomeIntExpr &&x) {
65964ab3302SCarolineConcatto   category_ = Category::Explicit;
66064ab3302SCarolineConcatto   expr_ = std::move(x);
66164ab3302SCarolineConcatto }
66264ab3302SCarolineConcatto 
AsFortran() const66364ab3302SCarolineConcatto std::string ParamValue::AsFortran() const {
66464ab3302SCarolineConcatto   switch (category_) {
66564ab3302SCarolineConcatto     SWITCH_COVERS_ALL_CASES
6661f879005STim Keith   case Category::Assumed:
6671f879005STim Keith     return "*";
6681f879005STim Keith   case Category::Deferred:
6691f879005STim Keith     return ":";
67064ab3302SCarolineConcatto   case Category::Explicit:
67164ab3302SCarolineConcatto     if (expr_) {
6728670e499SCaroline Concatto       std::string buf;
6738670e499SCaroline Concatto       llvm::raw_string_ostream ss{buf};
67464ab3302SCarolineConcatto       expr_->AsFortran(ss);
67564ab3302SCarolineConcatto       return ss.str();
67664ab3302SCarolineConcatto     } else {
67764ab3302SCarolineConcatto       return "";
67864ab3302SCarolineConcatto     }
67964ab3302SCarolineConcatto   }
68064ab3302SCarolineConcatto }
68164ab3302SCarolineConcatto 
operator <<(llvm::raw_ostream & o,const ParamValue & x)6828670e499SCaroline Concatto llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const ParamValue &x) {
68364ab3302SCarolineConcatto   return o << x.AsFortran();
68464ab3302SCarolineConcatto }
68564ab3302SCarolineConcatto 
IntrinsicTypeSpec(TypeCategory category,KindExpr && kind)68664ab3302SCarolineConcatto IntrinsicTypeSpec::IntrinsicTypeSpec(TypeCategory category, KindExpr &&kind)
68764ab3302SCarolineConcatto     : category_{category}, kind_{std::move(kind)} {
68864ab3302SCarolineConcatto   CHECK(category != TypeCategory::Derived);
68964ab3302SCarolineConcatto }
69064ab3302SCarolineConcatto 
KindAsFortran(const KindExpr & kind)69164ab3302SCarolineConcatto static std::string KindAsFortran(const KindExpr &kind) {
6928670e499SCaroline Concatto   std::string buf;
6938670e499SCaroline Concatto   llvm::raw_string_ostream ss{buf};
69464ab3302SCarolineConcatto   if (auto k{evaluate::ToInt64(kind)}) {
69564ab3302SCarolineConcatto     ss << *k; // emit unsuffixed kind code
69664ab3302SCarolineConcatto   } else {
69764ab3302SCarolineConcatto     kind.AsFortran(ss);
69864ab3302SCarolineConcatto   }
69964ab3302SCarolineConcatto   return ss.str();
70064ab3302SCarolineConcatto }
70164ab3302SCarolineConcatto 
AsFortran() const70264ab3302SCarolineConcatto std::string IntrinsicTypeSpec::AsFortran() const {
70364ab3302SCarolineConcatto   return parser::ToUpperCaseLetters(common::EnumToString(category_)) + '(' +
70464ab3302SCarolineConcatto       KindAsFortran(kind_) + ')';
70564ab3302SCarolineConcatto }
70664ab3302SCarolineConcatto 
operator <<(llvm::raw_ostream & os,const IntrinsicTypeSpec & x)7078670e499SCaroline Concatto llvm::raw_ostream &operator<<(
7088670e499SCaroline Concatto     llvm::raw_ostream &os, const IntrinsicTypeSpec &x) {
70964ab3302SCarolineConcatto   return os << x.AsFortran();
71064ab3302SCarolineConcatto }
71164ab3302SCarolineConcatto 
AsFortran() const71264ab3302SCarolineConcatto std::string CharacterTypeSpec::AsFortran() const {
71364ab3302SCarolineConcatto   return "CHARACTER(" + length_.AsFortran() + ',' + KindAsFortran(kind()) + ')';
71464ab3302SCarolineConcatto }
71564ab3302SCarolineConcatto 
operator <<(llvm::raw_ostream & os,const CharacterTypeSpec & x)7168670e499SCaroline Concatto llvm::raw_ostream &operator<<(
7178670e499SCaroline Concatto     llvm::raw_ostream &os, const CharacterTypeSpec &x) {
71864ab3302SCarolineConcatto   return os << x.AsFortran();
71964ab3302SCarolineConcatto }
72064ab3302SCarolineConcatto 
DeclTypeSpec(NumericTypeSpec && typeSpec)72164ab3302SCarolineConcatto DeclTypeSpec::DeclTypeSpec(NumericTypeSpec &&typeSpec)
72264ab3302SCarolineConcatto     : category_{Numeric}, typeSpec_{std::move(typeSpec)} {}
DeclTypeSpec(LogicalTypeSpec && typeSpec)72364ab3302SCarolineConcatto DeclTypeSpec::DeclTypeSpec(LogicalTypeSpec &&typeSpec)
72464ab3302SCarolineConcatto     : category_{Logical}, typeSpec_{std::move(typeSpec)} {}
DeclTypeSpec(const CharacterTypeSpec & typeSpec)72564ab3302SCarolineConcatto DeclTypeSpec::DeclTypeSpec(const CharacterTypeSpec &typeSpec)
72664ab3302SCarolineConcatto     : category_{Character}, typeSpec_{typeSpec} {}
DeclTypeSpec(CharacterTypeSpec && typeSpec)72764ab3302SCarolineConcatto DeclTypeSpec::DeclTypeSpec(CharacterTypeSpec &&typeSpec)
72864ab3302SCarolineConcatto     : category_{Character}, typeSpec_{std::move(typeSpec)} {}
DeclTypeSpec(Category category,const DerivedTypeSpec & typeSpec)72964ab3302SCarolineConcatto DeclTypeSpec::DeclTypeSpec(Category category, const DerivedTypeSpec &typeSpec)
73064ab3302SCarolineConcatto     : category_{category}, typeSpec_{typeSpec} {
73164ab3302SCarolineConcatto   CHECK(category == TypeDerived || category == ClassDerived);
73264ab3302SCarolineConcatto }
DeclTypeSpec(Category category,DerivedTypeSpec && typeSpec)73364ab3302SCarolineConcatto DeclTypeSpec::DeclTypeSpec(Category category, DerivedTypeSpec &&typeSpec)
73464ab3302SCarolineConcatto     : category_{category}, typeSpec_{std::move(typeSpec)} {
73564ab3302SCarolineConcatto   CHECK(category == TypeDerived || category == ClassDerived);
73664ab3302SCarolineConcatto }
DeclTypeSpec(Category category)73764ab3302SCarolineConcatto DeclTypeSpec::DeclTypeSpec(Category category) : category_{category} {
73864ab3302SCarolineConcatto   CHECK(category == TypeStar || category == ClassStar);
73964ab3302SCarolineConcatto }
IsNumeric(TypeCategory tc) const74064ab3302SCarolineConcatto bool DeclTypeSpec::IsNumeric(TypeCategory tc) const {
74164ab3302SCarolineConcatto   return category_ == Numeric && numericTypeSpec().category() == tc;
74264ab3302SCarolineConcatto }
IsSequenceType() const7432b790490SPete Steinfeld bool DeclTypeSpec::IsSequenceType() const {
7442b790490SPete Steinfeld   if (const DerivedTypeSpec * derivedType{AsDerived()}) {
7452b790490SPete Steinfeld     const auto *typeDetails{
7462b790490SPete Steinfeld         derivedType->typeSymbol().detailsIf<DerivedTypeDetails>()};
7472b790490SPete Steinfeld     return typeDetails && typeDetails->sequence();
7482b790490SPete Steinfeld   }
7492b790490SPete Steinfeld   return false;
7502b790490SPete Steinfeld }
7519623003eSTim Keith 
numericTypeSpec() const75264ab3302SCarolineConcatto const NumericTypeSpec &DeclTypeSpec::numericTypeSpec() const {
75364ab3302SCarolineConcatto   CHECK(category_ == Numeric);
75464ab3302SCarolineConcatto   return std::get<NumericTypeSpec>(typeSpec_);
75564ab3302SCarolineConcatto }
logicalTypeSpec() const75664ab3302SCarolineConcatto const LogicalTypeSpec &DeclTypeSpec::logicalTypeSpec() const {
75764ab3302SCarolineConcatto   CHECK(category_ == Logical);
75864ab3302SCarolineConcatto   return std::get<LogicalTypeSpec>(typeSpec_);
75964ab3302SCarolineConcatto }
operator ==(const DeclTypeSpec & that) const76064ab3302SCarolineConcatto bool DeclTypeSpec::operator==(const DeclTypeSpec &that) const {
76164ab3302SCarolineConcatto   return category_ == that.category_ && typeSpec_ == that.typeSpec_;
76264ab3302SCarolineConcatto }
76364ab3302SCarolineConcatto 
AsFortran() const76464ab3302SCarolineConcatto std::string DeclTypeSpec::AsFortran() const {
76564ab3302SCarolineConcatto   switch (category_) {
76664ab3302SCarolineConcatto     SWITCH_COVERS_ALL_CASES
7671f879005STim Keith   case Numeric:
7681f879005STim Keith     return numericTypeSpec().AsFortran();
7691f879005STim Keith   case Logical:
7701f879005STim Keith     return logicalTypeSpec().AsFortran();
7711f879005STim Keith   case Character:
7721f879005STim Keith     return characterTypeSpec().AsFortran();
7731f879005STim Keith   case TypeDerived:
774c14cf92bSPeter Klausler     if (derivedTypeSpec()
775c14cf92bSPeter Klausler             .typeSymbol()
776c14cf92bSPeter Klausler             .get<DerivedTypeDetails>()
777c14cf92bSPeter Klausler             .isDECStructure()) {
778c14cf92bSPeter Klausler       return "RECORD" + derivedTypeSpec().typeSymbol().name().ToString();
779c14cf92bSPeter Klausler     } else {
7801f879005STim Keith       return "TYPE(" + derivedTypeSpec().AsFortran() + ')';
781c14cf92bSPeter Klausler     }
7821f879005STim Keith   case ClassDerived:
7831f879005STim Keith     return "CLASS(" + derivedTypeSpec().AsFortran() + ')';
7841f879005STim Keith   case TypeStar:
7851f879005STim Keith     return "TYPE(*)";
7861f879005STim Keith   case ClassStar:
7871f879005STim Keith     return "CLASS(*)";
78864ab3302SCarolineConcatto   }
78964ab3302SCarolineConcatto }
79064ab3302SCarolineConcatto 
operator <<(llvm::raw_ostream & o,const DeclTypeSpec & x)7918670e499SCaroline Concatto llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const DeclTypeSpec &x) {
79264ab3302SCarolineConcatto   return o << x.AsFortran();
79364ab3302SCarolineConcatto }
79464ab3302SCarolineConcatto 
set_symbol(const Symbol & symbol)79564ab3302SCarolineConcatto void ProcInterface::set_symbol(const Symbol &symbol) {
79664ab3302SCarolineConcatto   CHECK(!type_);
79764ab3302SCarolineConcatto   symbol_ = &symbol;
79864ab3302SCarolineConcatto }
set_type(const DeclTypeSpec & type)79964ab3302SCarolineConcatto void ProcInterface::set_type(const DeclTypeSpec &type) {
80064ab3302SCarolineConcatto   CHECK(!symbol_);
80164ab3302SCarolineConcatto   type_ = &type;
80264ab3302SCarolineConcatto }
803ebe74d95Speter klausler 
8041f879005STim Keith } // namespace Fortran::semantics
805