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