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