[flang][NFC] Refactor derived type instantiation
authorTim Keith <tkeith@nvidia.com>
Wed, 22 Apr 2020 22:26:29 +0000 (15:26 -0700)
committerTim Keith <tkeith@nvidia.com>
Thu, 23 Apr 2020 15:29:47 +0000 (08:29 -0700)
Summary:
Move InstantiateComponent and InstantiateIntrinsicType from symbol.cpp
to type.cpp as that is where they are called.

Put both in InstantiateHelper class to better isolate them.
Add CreateDerivedTypeSpec in InstantiateHelper.

Add non-const forms for AsIntrinsic and AsDerived to avoid const_cast.

No functional changes.

Reviewers: DavidTruby, klausler, PeteSteinfeld, jdoerfert

Reviewed By: klausler

Subscribers: llvm-commits

Tags: #flang, #llvm

Differential Revision: https://reviews.llvm.org/D78678

flang/include/flang/Semantics/symbol.h
flang/include/flang/Semantics/type.h
flang/lib/Semantics/symbol.cpp
flang/lib/Semantics/type.cpp

index 947535c..7ac48db 100644 (file)
@@ -659,9 +659,6 @@ public:
   // for a parameterized derived type instantiation with the instance's scope.
   const DerivedTypeSpec *GetParentTypeSpec(const Scope * = nullptr) const;
 
-  // Clones the Symbol into a parameterized derived type instance.
-  Symbol &InstantiateComponent(Scope &, SemanticsContext &) const;
-
 private:
   const Scope *owner_;
   SourceName name_;
index cc20318..cf41721 100644 (file)
@@ -353,28 +353,9 @@ public:
   }
 
   IntrinsicTypeSpec *AsIntrinsic();
-  const IntrinsicTypeSpec *AsIntrinsic() const {
-    switch (category_) {
-    case Numeric:
-      return &std::get<NumericTypeSpec>(typeSpec_);
-    case Logical:
-      return &std::get<LogicalTypeSpec>(typeSpec_);
-    case Character:
-      return &std::get<CharacterTypeSpec>(typeSpec_);
-    default:
-      return nullptr;
-    }
-  }
-
-  const DerivedTypeSpec *AsDerived() const {
-    switch (category_) {
-    case TypeDerived:
-    case ClassDerived:
-      return &std::get<DerivedTypeSpec>(typeSpec_);
-    default:
-      return nullptr;
-    }
-  }
+  const IntrinsicTypeSpec *AsIntrinsic() const;
+  DerivedTypeSpec *AsDerived();
+  const DerivedTypeSpec *AsDerived() const;
 
   std::string AsFortran() const;
 
index c80b669..19f8b92 100644 (file)
@@ -550,124 +550,6 @@ const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
   }
 }
 
-// Utility routine for InstantiateComponent(): applies type
-// parameter values to an intrinsic type spec.
-static const DeclTypeSpec &InstantiateIntrinsicType(Scope &scope,
-    const DeclTypeSpec &spec, SemanticsContext &semanticsContext) {
-  const IntrinsicTypeSpec &intrinsic{DEREF(spec.AsIntrinsic())};
-  if (evaluate::ToInt64(intrinsic.kind())) {
-    return spec; // KIND is already a known constant
-  }
-  // The expression was not originally constant, but now it must be so
-  // in the context of a parameterized derived type instantiation.
-  KindExpr copy{intrinsic.kind()};
-  evaluate::FoldingContext &foldingContext{semanticsContext.foldingContext()};
-  copy = evaluate::Fold(foldingContext, std::move(copy));
-  int kind{semanticsContext.GetDefaultKind(intrinsic.category())};
-  if (auto value{evaluate::ToInt64(copy)}) {
-    if (evaluate::IsValidKindOfIntrinsicType(intrinsic.category(), *value)) {
-      kind = *value;
-    } else {
-      foldingContext.messages().Say(
-          "KIND parameter value (%jd) of intrinsic type %s "
-          "did not resolve to a supported value"_err_en_US,
-          *value,
-          parser::ToUpperCaseLetters(
-              common::EnumToString(intrinsic.category())));
-    }
-  }
-  switch (spec.category()) {
-  case DeclTypeSpec::Numeric:
-    return scope.MakeNumericType(intrinsic.category(), KindExpr{kind});
-  case DeclTypeSpec::Logical: //
-    return scope.MakeLogicalType(KindExpr{kind});
-  case DeclTypeSpec::Character:
-    return scope.MakeCharacterType(
-        ParamValue{spec.characterTypeSpec().length()}, KindExpr{kind});
-  default:
-    CRASH_NO_CASE;
-  }
-}
-
-Symbol &Symbol::InstantiateComponent(
-    Scope &scope, SemanticsContext &context) const {
-  auto &foldingContext{context.foldingContext()};
-  auto pair{scope.try_emplace(name(), attrs())};
-  Symbol &result{*pair.first->second};
-  if (!pair.second) {
-    // Symbol was already present in the scope, which can only happen
-    // in the case of type parameters.
-    CHECK(has<TypeParamDetails>());
-    return result;
-  }
-  result.attrs() = attrs();
-  result.flags() = flags();
-  result.set_details(common::Clone(details()));
-  if (auto *details{result.detailsIf<ObjectEntityDetails>()}) {
-    if (DeclTypeSpec * origType{result.GetType()}) {
-      if (const DerivedTypeSpec * derived{origType->AsDerived()}) {
-        DerivedTypeSpec newSpec{*derived};
-        newSpec.CookParameters(foldingContext); // enables AddParamValue()
-        if (test(Symbol::Flag::ParentComp)) {
-          // Forward any explicit type parameter values from the
-          // derived type spec under instantiation that define type parameters
-          // of the parent component to the derived type spec of the
-          // parent component.
-          const DerivedTypeSpec &instanceSpec{
-              DEREF(foldingContext.pdtInstance())};
-          for (const auto &[name, value] : instanceSpec.parameters()) {
-            if (scope.find(name) == scope.end()) {
-              newSpec.AddParamValue(name, ParamValue{value});
-            }
-          }
-        }
-        details->ReplaceType(FindOrInstantiateDerivedType(
-            scope, std::move(newSpec), context, origType->category()));
-      } else if (origType->AsIntrinsic()) {
-        details->ReplaceType(
-            InstantiateIntrinsicType(scope, *origType, context));
-      } else if (origType->category() != DeclTypeSpec::ClassStar) {
-        DIE("instantiated component has type that is "
-            "neither intrinsic, derived, nor CLASS(*)");
-      }
-    }
-    details->set_init(
-        evaluate::Fold(foldingContext, std::move(details->init())));
-    for (ShapeSpec &dim : details->shape()) {
-      if (dim.lbound().isExplicit()) {
-        dim.lbound().SetExplicit(
-            Fold(foldingContext, std::move(dim.lbound().GetExplicit())));
-      }
-      if (dim.ubound().isExplicit()) {
-        dim.ubound().SetExplicit(
-            Fold(foldingContext, std::move(dim.ubound().GetExplicit())));
-      }
-    }
-    for (ShapeSpec &dim : details->coshape()) {
-      if (dim.lbound().isExplicit()) {
-        dim.lbound().SetExplicit(
-            Fold(foldingContext, std::move(dim.lbound().GetExplicit())));
-      }
-      if (dim.ubound().isExplicit()) {
-        dim.ubound().SetExplicit(
-            Fold(foldingContext, std::move(dim.ubound().GetExplicit())));
-      }
-    }
-  } else if (!attrs_.test(Attr::NOPASS)) {
-    std::visit(
-        [&result](const auto &x) {
-          using Ty = std::decay_t<decltype(x)>;
-          if constexpr (std::is_base_of_v<WithPassArg, Ty>) {
-            if (auto passName{x.passName()}) {
-              result.get<Ty>().set_passName(*passName);
-            }
-          }
-        },
-        details_);
-  }
-  return result;
-}
-
 void DerivedTypeDetails::add_component(const Symbol &symbol) {
   if (symbol.test(Symbol::Flag::ParentComp)) {
     CHECK(componentNames_.empty());
index f4fc7cb..2b7de8f 100644 (file)
@@ -186,6 +186,29 @@ ParamValue *DerivedTypeSpec::FindParameter(SourceName target) {
       const_cast<const DerivedTypeSpec *>(this)->FindParameter(target));
 }
 
+class InstantiateHelper {
+public:
+  InstantiateHelper(SemanticsContext &context, Scope &scope)
+      : context_{context}, scope_{scope} {}
+  // Instantiate components from fromScope into scope_
+  void InstantiateComponents(const Scope &);
+
+private:
+  evaluate::FoldingContext &foldingContext() {
+    return context_.foldingContext();
+  }
+  template <typename T> T Fold(T &&expr) {
+    return evaluate::Fold(foldingContext(), std::move(expr));
+  }
+  void InstantiateComponent(const Symbol &);
+  const DeclTypeSpec *InstantiateType(const Symbol &);
+  const DeclTypeSpec &InstantiateIntrinsicType(const DeclTypeSpec &);
+  DerivedTypeSpec CreateDerivedTypeSpec(const DerivedTypeSpec &, bool);
+
+  SemanticsContext &context_;
+  Scope &scope_;
+};
+
 void DerivedTypeSpec::Instantiate(
     Scope &containingScope, SemanticsContext &context) {
   if (instantiated_) {
@@ -204,14 +227,13 @@ void DerivedTypeSpec::Instantiate(
   const Scope &typeScope{DEREF(typeSymbol_.scope())};
   if (!MightBeParameterized()) {
     scope_ = &typeScope;
-    for (const auto &pair : typeScope) {
-      const Symbol &symbol{*pair.second};
-      if (const DeclTypeSpec * type{symbol.GetType()}) {
-        if (const DerivedTypeSpec * derived{type->AsDerived()}) {
+    for (auto &pair : typeScope) {
+      Symbol &symbol{*pair.second};
+      if (DeclTypeSpec * type{symbol.GetType()}) {
+        if (DerivedTypeSpec * derived{type->AsDerived()}) {
           if (!(derived->IsForwardReferenced() &&
                   IsAllocatableOrPointer(symbol))) {
-            auto &instantiatable{*const_cast<DerivedTypeSpec *>(derived)};
-            instantiatable.Instantiate(containingScope, context);
+            derived->Instantiate(containingScope, context);
           }
         }
       }
@@ -264,12 +286,121 @@ void DerivedTypeSpec::Instantiate(
   // type's scope into the new instance.
   auto restorer{foldingContext.WithPDTInstance(*this)};
   newScope.AddSourceRange(typeScope.sourceRange());
-  for (const auto &pair : typeScope) {
-    const Symbol &symbol{*pair.second};
-    symbol.InstantiateComponent(newScope, context);
+  InstantiateHelper{context, newScope}.InstantiateComponents(typeScope);
+}
+
+void InstantiateHelper::InstantiateComponents(const Scope &fromScope) {
+  for (const auto &pair : fromScope) {
+    InstantiateComponent(*pair.second);
+  }
+}
+
+void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {
+  auto pair{scope_.try_emplace(
+      oldSymbol.name(), oldSymbol.attrs(), common::Clone(oldSymbol.details()))};
+  Symbol &newSymbol{*pair.first->second};
+  if (!pair.second) {
+    // Symbol was already present in the scope, which can only happen
+    // in the case of type parameters.
+    CHECK(oldSymbol.has<TypeParamDetails>());
+    return;
+  }
+  newSymbol.flags() = oldSymbol.flags();
+  if (auto *details{newSymbol.detailsIf<ObjectEntityDetails>()}) {
+    if (const DeclTypeSpec * newType{InstantiateType(newSymbol)}) {
+      details->ReplaceType(*newType);
+    }
+    details->set_init(Fold(std::move(details->init())));
+    for (ShapeSpec &dim : details->shape()) {
+      if (dim.lbound().isExplicit()) {
+        dim.lbound().SetExplicit(Fold(std::move(dim.lbound().GetExplicit())));
+      }
+      if (dim.ubound().isExplicit()) {
+        dim.ubound().SetExplicit(Fold(std::move(dim.ubound().GetExplicit())));
+      }
+    }
+    for (ShapeSpec &dim : details->coshape()) {
+      if (dim.lbound().isExplicit()) {
+        dim.lbound().SetExplicit(Fold(std::move(dim.lbound().GetExplicit())));
+      }
+      if (dim.ubound().isExplicit()) {
+        dim.ubound().SetExplicit(Fold(std::move(dim.ubound().GetExplicit())));
+      }
+    }
+  }
+}
+
+const DeclTypeSpec *InstantiateHelper::InstantiateType(const Symbol &symbol) {
+  const DeclTypeSpec *type{symbol.GetType()};
+  if (!type) {
+    return nullptr; // error has occurred
+  } else if (const DerivedTypeSpec * spec{type->AsDerived()}) {
+    return &FindOrInstantiateDerivedType(scope_,
+        CreateDerivedTypeSpec(*spec, symbol.test(Symbol::Flag::ParentComp)),
+        context_, type->category());
+  } else if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) {
+    return &InstantiateIntrinsicType(*type);
+  } else if (type->category() == DeclTypeSpec::ClassStar) {
+    return type;
+  } else {
+    common::die("InstantiateType: %s", type->AsFortran().c_str());
+  }
+}
+
+// Apply type parameter values to an intrinsic type spec.
+const DeclTypeSpec &InstantiateHelper::InstantiateIntrinsicType(
+    const DeclTypeSpec &spec) {
+  const IntrinsicTypeSpec &intrinsic{DEREF(spec.AsIntrinsic())};
+  if (evaluate::ToInt64(intrinsic.kind())) {
+    return spec; // KIND is already a known constant
+  }
+  // The expression was not originally constant, but now it must be so
+  // in the context of a parameterized derived type instantiation.
+  KindExpr copy{Fold(common::Clone(intrinsic.kind()))};
+  int kind{context_.GetDefaultKind(intrinsic.category())};
+  if (auto value{evaluate::ToInt64(copy)}) {
+    if (evaluate::IsValidKindOfIntrinsicType(intrinsic.category(), *value)) {
+      kind = *value;
+    } else {
+      foldingContext().messages().Say(
+          "KIND parameter value (%jd) of intrinsic type %s "
+          "did not resolve to a supported value"_err_en_US,
+          *value,
+          parser::ToUpperCaseLetters(EnumToString(intrinsic.category())));
+    }
+  }
+  switch (spec.category()) {
+  case DeclTypeSpec::Numeric:
+    return scope_.MakeNumericType(intrinsic.category(), KindExpr{kind});
+  case DeclTypeSpec::Logical:
+    return scope_.MakeLogicalType(KindExpr{kind});
+  case DeclTypeSpec::Character:
+    return scope_.MakeCharacterType(
+        ParamValue{spec.characterTypeSpec().length()}, KindExpr{kind});
+  default:
+    CRASH_NO_CASE;
   }
 }
 
+DerivedTypeSpec InstantiateHelper::CreateDerivedTypeSpec(
+    const DerivedTypeSpec &spec, bool isParentComp) {
+  DerivedTypeSpec result{spec};
+  result.CookParameters(foldingContext()); // enables AddParamValue()
+  if (isParentComp) {
+    // Forward any explicit type parameter values from the
+    // derived type spec under instantiation that define type parameters
+    // of the parent component to the derived type spec of the
+    // parent component.
+    const DerivedTypeSpec &instanceSpec{DEREF(foldingContext().pdtInstance())};
+    for (const auto &[name, value] : instanceSpec.parameters()) {
+      if (scope_.find(name) == scope_.end()) {
+        result.AddParamValue(name, ParamValue{value});
+      }
+    }
+  }
+  return result;
+}
+
 std::string DerivedTypeSpec::AsFortran() const {
   std::string buf;
   llvm::raw_string_ostream ss{buf};
@@ -480,10 +611,36 @@ bool DeclTypeSpec::IsSequenceType() const {
   }
   return false;
 }
+
 IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() {
-  return const_cast<IntrinsicTypeSpec *>(
-      const_cast<const DeclTypeSpec *>(this)->AsIntrinsic());
+  switch (category_) {
+  case Numeric:
+    return &std::get<NumericTypeSpec>(typeSpec_);
+  case Logical:
+    return &std::get<LogicalTypeSpec>(typeSpec_);
+  case Character:
+    return &std::get<CharacterTypeSpec>(typeSpec_);
+  default:
+    return nullptr;
+  }
+}
+const IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() const {
+  return const_cast<DeclTypeSpec *>(this)->AsIntrinsic();
+}
+
+DerivedTypeSpec *DeclTypeSpec::AsDerived() {
+  switch (category_) {
+  case TypeDerived:
+  case ClassDerived:
+    return &std::get<DerivedTypeSpec>(typeSpec_);
+  default:
+    return nullptr;
+  }
+}
+const DerivedTypeSpec *DeclTypeSpec::AsDerived() const {
+  return const_cast<DeclTypeSpec *>(this)->AsDerived();
 }
+
 const NumericTypeSpec &DeclTypeSpec::numericTypeSpec() const {
   CHECK(category_ == Numeric);
   return std::get<NumericTypeSpec>(typeSpec_);