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 (evaluate::IsValidKindOfIntrinsicType(intrinsic.category(), *value)) {
522       kind = *value;
523     } else {
524       foldingContext().messages().Say(symbolName,
525           "KIND parameter value (%jd) of intrinsic type %s "
526           "did not resolve to a supported value"_err_en_US,
527           *value,
528           parser::ToUpperCaseLetters(EnumToString(intrinsic.category())));
529     }
530   }
531   switch (spec.category()) {
532   case DeclTypeSpec::Numeric:
533     return scope_.MakeNumericType(intrinsic.category(), KindExpr{kind});
534   case DeclTypeSpec::Logical:
535     return scope_.MakeLogicalType(KindExpr{kind});
536   case DeclTypeSpec::Character:
537     return scope_.MakeCharacterType(
538         FoldCharacterLength(foldingContext(), spec.characterTypeSpec()),
539         KindExpr{kind});
540   default:
541     CRASH_NO_CASE;
542   }
543 }
544 
545 DerivedTypeSpec InstantiateHelper::CreateDerivedTypeSpec(
546     const DerivedTypeSpec &spec, bool isParentComp) {
547   DerivedTypeSpec result{spec};
548   result.CookParameters(foldingContext()); // enables AddParamValue()
549   if (isParentComp) {
550     // Forward any explicit type parameter values from the
551     // derived type spec under instantiation that define type parameters
552     // of the parent component to the derived type spec of the
553     // parent component.
554     const DerivedTypeSpec &instanceSpec{DEREF(foldingContext().pdtInstance())};
555     for (const auto &[name, value] : instanceSpec.parameters()) {
556       if (scope_.find(name) == scope_.end()) {
557         result.AddParamValue(name, ParamValue{value});
558       }
559     }
560   }
561   return result;
562 }
563 
564 std::string DerivedTypeSpec::AsFortran() const {
565   std::string buf;
566   llvm::raw_string_ostream ss{buf};
567   ss << name_;
568   if (!rawParameters_.empty()) {
569     CHECK(parameters_.empty());
570     ss << '(';
571     bool first = true;
572     for (const auto &[maybeKeyword, value] : rawParameters_) {
573       if (first) {
574         first = false;
575       } else {
576         ss << ',';
577       }
578       if (maybeKeyword) {
579         ss << maybeKeyword->v.source.ToString() << '=';
580       }
581       ss << value.AsFortran();
582     }
583     ss << ')';
584   } else if (!parameters_.empty()) {
585     ss << '(';
586     bool first = true;
587     for (const auto &[name, value] : parameters_) {
588       if (first) {
589         first = false;
590       } else {
591         ss << ',';
592       }
593       ss << name.ToString() << '=' << value.AsFortran();
594     }
595     ss << ')';
596   }
597   return ss.str();
598 }
599 
600 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const DerivedTypeSpec &x) {
601   return o << x.AsFortran();
602 }
603 
604 Bound::Bound(common::ConstantSubscript bound) : expr_{bound} {}
605 
606 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const Bound &x) {
607   if (x.isStar()) {
608     o << '*';
609   } else if (x.isColon()) {
610     o << ':';
611   } else if (x.expr_) {
612     x.expr_->AsFortran(o);
613   } else {
614     o << "<no-expr>";
615   }
616   return o;
617 }
618 
619 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const ShapeSpec &x) {
620   if (x.lb_.isStar()) {
621     CHECK(x.ub_.isStar());
622     o << "..";
623   } else {
624     if (!x.lb_.isColon()) {
625       o << x.lb_;
626     }
627     o << ':';
628     if (!x.ub_.isColon()) {
629       o << x.ub_;
630     }
631   }
632   return o;
633 }
634 
635 llvm::raw_ostream &operator<<(
636     llvm::raw_ostream &os, const ArraySpec &arraySpec) {
637   char sep{'('};
638   for (auto &shape : arraySpec) {
639     os << sep << shape;
640     sep = ',';
641   }
642   if (sep == ',') {
643     os << ')';
644   }
645   return os;
646 }
647 
648 ParamValue::ParamValue(MaybeIntExpr &&expr, common::TypeParamAttr attr)
649     : attr_{attr}, expr_{std::move(expr)} {}
650 ParamValue::ParamValue(SomeIntExpr &&expr, common::TypeParamAttr attr)
651     : attr_{attr}, expr_{std::move(expr)} {}
652 ParamValue::ParamValue(
653     common::ConstantSubscript value, common::TypeParamAttr attr)
654     : ParamValue(SomeIntExpr{evaluate::Expr<evaluate::SubscriptInteger>{value}},
655           attr) {}
656 
657 void ParamValue::SetExplicit(SomeIntExpr &&x) {
658   category_ = Category::Explicit;
659   expr_ = std::move(x);
660 }
661 
662 std::string ParamValue::AsFortran() const {
663   switch (category_) {
664     SWITCH_COVERS_ALL_CASES
665   case Category::Assumed:
666     return "*";
667   case Category::Deferred:
668     return ":";
669   case Category::Explicit:
670     if (expr_) {
671       std::string buf;
672       llvm::raw_string_ostream ss{buf};
673       expr_->AsFortran(ss);
674       return ss.str();
675     } else {
676       return "";
677     }
678   }
679 }
680 
681 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const ParamValue &x) {
682   return o << x.AsFortran();
683 }
684 
685 IntrinsicTypeSpec::IntrinsicTypeSpec(TypeCategory category, KindExpr &&kind)
686     : category_{category}, kind_{std::move(kind)} {
687   CHECK(category != TypeCategory::Derived);
688 }
689 
690 static std::string KindAsFortran(const KindExpr &kind) {
691   std::string buf;
692   llvm::raw_string_ostream ss{buf};
693   if (auto k{evaluate::ToInt64(kind)}) {
694     ss << *k; // emit unsuffixed kind code
695   } else {
696     kind.AsFortran(ss);
697   }
698   return ss.str();
699 }
700 
701 std::string IntrinsicTypeSpec::AsFortran() const {
702   return parser::ToUpperCaseLetters(common::EnumToString(category_)) + '(' +
703       KindAsFortran(kind_) + ')';
704 }
705 
706 llvm::raw_ostream &operator<<(
707     llvm::raw_ostream &os, const IntrinsicTypeSpec &x) {
708   return os << x.AsFortran();
709 }
710 
711 std::string CharacterTypeSpec::AsFortran() const {
712   return "CHARACTER(" + length_.AsFortran() + ',' + KindAsFortran(kind()) + ')';
713 }
714 
715 llvm::raw_ostream &operator<<(
716     llvm::raw_ostream &os, const CharacterTypeSpec &x) {
717   return os << x.AsFortran();
718 }
719 
720 DeclTypeSpec::DeclTypeSpec(NumericTypeSpec &&typeSpec)
721     : category_{Numeric}, typeSpec_{std::move(typeSpec)} {}
722 DeclTypeSpec::DeclTypeSpec(LogicalTypeSpec &&typeSpec)
723     : category_{Logical}, typeSpec_{std::move(typeSpec)} {}
724 DeclTypeSpec::DeclTypeSpec(const CharacterTypeSpec &typeSpec)
725     : category_{Character}, typeSpec_{typeSpec} {}
726 DeclTypeSpec::DeclTypeSpec(CharacterTypeSpec &&typeSpec)
727     : category_{Character}, typeSpec_{std::move(typeSpec)} {}
728 DeclTypeSpec::DeclTypeSpec(Category category, const DerivedTypeSpec &typeSpec)
729     : category_{category}, typeSpec_{typeSpec} {
730   CHECK(category == TypeDerived || category == ClassDerived);
731 }
732 DeclTypeSpec::DeclTypeSpec(Category category, DerivedTypeSpec &&typeSpec)
733     : category_{category}, typeSpec_{std::move(typeSpec)} {
734   CHECK(category == TypeDerived || category == ClassDerived);
735 }
736 DeclTypeSpec::DeclTypeSpec(Category category) : category_{category} {
737   CHECK(category == TypeStar || category == ClassStar);
738 }
739 bool DeclTypeSpec::IsNumeric(TypeCategory tc) const {
740   return category_ == Numeric && numericTypeSpec().category() == tc;
741 }
742 bool DeclTypeSpec::IsSequenceType() const {
743   if (const DerivedTypeSpec * derivedType{AsDerived()}) {
744     const auto *typeDetails{
745         derivedType->typeSymbol().detailsIf<DerivedTypeDetails>()};
746     return typeDetails && typeDetails->sequence();
747   }
748   return false;
749 }
750 
751 const NumericTypeSpec &DeclTypeSpec::numericTypeSpec() const {
752   CHECK(category_ == Numeric);
753   return std::get<NumericTypeSpec>(typeSpec_);
754 }
755 const LogicalTypeSpec &DeclTypeSpec::logicalTypeSpec() const {
756   CHECK(category_ == Logical);
757   return std::get<LogicalTypeSpec>(typeSpec_);
758 }
759 bool DeclTypeSpec::operator==(const DeclTypeSpec &that) const {
760   return category_ == that.category_ && typeSpec_ == that.typeSpec_;
761 }
762 
763 std::string DeclTypeSpec::AsFortran() const {
764   switch (category_) {
765     SWITCH_COVERS_ALL_CASES
766   case Numeric:
767     return numericTypeSpec().AsFortran();
768   case Logical:
769     return logicalTypeSpec().AsFortran();
770   case Character:
771     return characterTypeSpec().AsFortran();
772   case TypeDerived:
773     if (derivedTypeSpec()
774             .typeSymbol()
775             .get<DerivedTypeDetails>()
776             .isDECStructure()) {
777       return "RECORD" + derivedTypeSpec().typeSymbol().name().ToString();
778     } else {
779       return "TYPE(" + derivedTypeSpec().AsFortran() + ')';
780     }
781   case ClassDerived:
782     return "CLASS(" + derivedTypeSpec().AsFortran() + ')';
783   case TypeStar:
784     return "TYPE(*)";
785   case ClassStar:
786     return "CLASS(*)";
787   }
788 }
789 
790 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const DeclTypeSpec &x) {
791   return o << x.AsFortran();
792 }
793 
794 void ProcInterface::set_symbol(const Symbol &symbol) {
795   CHECK(!type_);
796   symbol_ = &symbol;
797 }
798 void ProcInterface::set_type(const DeclTypeSpec &type) {
799   CHECK(!symbol_);
800   type_ = &type;
801 }
802 
803 } // namespace Fortran::semantics
804