}
}
-// 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());
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_) {
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);
}
}
}
// 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};
}
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_);