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