[flang] Continue work on name resolution
authorTim Keith <tkeith@nvidia.com>
Fri, 30 Mar 2018 20:57:23 +0000 (13:57 -0700)
committerGitHub <noreply@github.com>
Mon, 2 Apr 2018 17:49:22 +0000 (10:49 -0700)
Enhance DeclTypeSpecVisitor to find derived-type-specs, including with
type parameter values.

Change DerivedTypeSpec so it only needs the name of the derived type,
not the definition, as that isn't necessarily known when we encounter
it.

Fix how memory is managed in DeclTypeSpec: Intrinsic type specs aren't a
problem -- they are one of a few types that live throughout the program.
Derived type specs are dynamically allocated and the memory is owned by
the DeclTypeSpec -- it allocates it when a DeclTypeSpec for a derived
type is created and deletes it when it is destroyed. Pass around
references to TypeSpecs rather than pointers as they can never be null.

In AttrsVisitor, DeclTypeSpecVisitor, ResolveNamesVisitor: make most
functions out-of-line to clean up the class declaration.

In AttrsVisitor, use preprocessor to simplify the simple case of
encountering a parse-tree class causing an attribute to be set.
Handle all such attributes.

Remove old testing code from type.cc.

Remove some of the declarations for IntExpr and IntConst -- they are
only placeholder classes anyway. Don't distinguish kind and length
parameter values.

Original-commit: flang-compiler/f18@e172b5121274a3cfc597f062da1ea32aa56039d9
Reviewed-on: https://github.com/flang-compiler/f18/pull/36
Tree-same-pre-rewrite: false

flang/lib/semantics/make-types.cc
flang/lib/semantics/resolve-names.cc
flang/lib/semantics/symbol.h
flang/lib/semantics/type.cc
flang/lib/semantics/type.h

index b27e309..96a4ba0 100644 (file)
@@ -337,15 +337,7 @@ static KindParamValue GetKindParamValue(
 }
 
 static const IntExpr *GetIntExpr(const parser::ScalarIntExpr &x) {
-  const parser::Expr &expr = *x.thing.thing;
-  if (std::holds_alternative<parser::LiteralConstant>(expr.u)) {
-    const auto &lit = std::get<parser::LiteralConstant>(expr.u);
-    if (std::holds_alternative<parser::IntLiteralConstant>(lit.u)) {
-      const auto &intLit = std::get<parser::IntLiteralConstant>(lit.u);
-      return &IntConst::Make(std::get<std::uint64_t>(intLit.t));
-    }
-  }
-  return new IntExpr();  // TODO
+  return new IntExpr(x);
 }
 
 static Bound GetBound(const parser::SpecificationExpr &x) {
index 5e12e3e..6a02421 100644 (file)
@@ -15,34 +15,42 @@ namespace Fortran::semantics {
 // Provide Post methods to collect attributes into a member variable.
 class AttrsVisitor {
 public:
-  void beginAttrs() {
-    CHECK(!attrs_);
-    attrs_ = std::make_unique<Attrs>();
-  }
-  Attrs endAttrs() {
-    const auto result = attrs_ ? *attrs_ : Attrs::EMPTY;
-    attrs_.reset();
-    return result;
-  }
+  void beginAttrs();
+  Attrs endAttrs();
+  void Post(const parser::LanguageBindingSpec &x);
+  bool Pre(const parser::AccessSpec &x);
+  bool Pre(const parser::IntentSpec &x);
 
-  void Post(const parser::LanguageBindingSpec &x) {
-    attrs_->Set(Attr::BIND_C);
-    if (x.v) {
-      // TODO: set langBindingName_ from ScalarDefaultCharConstantExpr
-    }
-  }
-  void Post(const parser::PrefixSpec::Elemental &) {
-    attrs_->Set(Attr::ELEMENTAL);
-  }
-  void Post(const parser::PrefixSpec::Impure &) { attrs_->Set(Attr::IMPURE); }
-  void Post(const parser::PrefixSpec::Module &) { attrs_->Set(Attr::MODULE); }
-  void Post(const parser::PrefixSpec::Non_Recursive &) {
-    attrs_->Set(Attr::NON_RECURSIVE);
-  }
-  void Post(const parser::PrefixSpec::Pure &) { attrs_->Set(Attr::PURE); }
-  void Post(const parser::PrefixSpec::Recursive &) {
-    attrs_->Set(Attr::RECURSIVE);
+// Simple case: encountering CLASSNAME causes ATTRNAME to be set.
+#define HANDLE_ATTR_CLASS(CLASSNAME, ATTRNAME) \
+  bool Pre(const parser::CLASSNAME &) { \
+    attrs_->Set(Attr::ATTRNAME); \
+    return false; \
   }
+  HANDLE_ATTR_CLASS(PrefixSpec::Elemental, ELEMENTAL)
+  HANDLE_ATTR_CLASS(PrefixSpec::Impure, IMPURE)
+  HANDLE_ATTR_CLASS(PrefixSpec::Module, MODULE)
+  HANDLE_ATTR_CLASS(PrefixSpec::Non_Recursive, NON_RECURSIVE)
+  HANDLE_ATTR_CLASS(PrefixSpec::Pure, PURE)
+  HANDLE_ATTR_CLASS(PrefixSpec::Recursive, RECURSIVE)
+  HANDLE_ATTR_CLASS(TypeAttrSpec::BindC, BIND_C)
+  HANDLE_ATTR_CLASS(Abstract, ABSTRACT)
+  HANDLE_ATTR_CLASS(Allocatable, ALLOCATABLE)
+  HANDLE_ATTR_CLASS(Asynchronous, ASYNCHRONOUS)
+  HANDLE_ATTR_CLASS(Contiguous, CONTIGUOUS)
+  HANDLE_ATTR_CLASS(External, EXTERNAL)
+  HANDLE_ATTR_CLASS(Intrinsic, INTRINSIC)
+  HANDLE_ATTR_CLASS(NoPass, NOPASS)
+  HANDLE_ATTR_CLASS(Optional, OPTIONAL)
+  HANDLE_ATTR_CLASS(Parameter, PARAMETER)
+  HANDLE_ATTR_CLASS(Pass, PASS)
+  HANDLE_ATTR_CLASS(Pointer, POINTER)
+  HANDLE_ATTR_CLASS(Protected, PROTECTED)
+  HANDLE_ATTR_CLASS(Save, SAVE)
+  HANDLE_ATTR_CLASS(Target, TARGET)
+  HANDLE_ATTR_CLASS(Value, VALUE)
+  HANDLE_ATTR_CLASS(Volatile, VOLATILE)
+#undef HANDLE_ATTR_CLASS
 
 protected:
   std::unique_ptr<Attrs> attrs_;
@@ -53,63 +61,33 @@ protected:
 class DeclTypeSpecVisitor : public AttrsVisitor {
 public:
   using AttrsVisitor::Post;
-
-  void beginDeclTypeSpec() {
-    CHECK(!expectDeclTypeSpec_);
-    expectDeclTypeSpec_ = true;
-  }
-  std::optional<DeclTypeSpec> getDeclTypeSpec() {
-    return declTypeSpec_ ? *declTypeSpec_.get() : std::optional<DeclTypeSpec>();
-  }
-  void endDeclTypeSpec() {
-    CHECK(expectDeclTypeSpec_);
-    expectDeclTypeSpec_ = false;
-    declTypeSpec_.reset();
-  }
-
-  bool Pre(const parser::IntegerTypeSpec &x) {
-    MakeIntrinsic(IntegerTypeSpec::Make(GetKindParamValue(x.v)));
-    return false;
-  }
-  bool Pre(const parser::IntrinsicTypeSpec::Logical &x) {
-    MakeIntrinsic(LogicalTypeSpec::Make(GetKindParamValue(x.kind)));
-    return false;
-  }
-  bool Pre(const parser::IntrinsicTypeSpec::Real &x) {
-    MakeIntrinsic(RealTypeSpec::Make(GetKindParamValue(x.kind)));
-    return false;
-  }
-  bool Pre(const parser::IntrinsicTypeSpec::Complex &x) {
-    MakeIntrinsic(ComplexTypeSpec::Make(GetKindParamValue(x.kind)));
-    return false;
-  }
+  using AttrsVisitor::Pre;
+  void beginDeclTypeSpec();
+  void endDeclTypeSpec();
+  bool Pre(const parser::IntegerTypeSpec &);
+  bool Pre(const parser::IntrinsicTypeSpec::Logical &);
+  bool Pre(const parser::IntrinsicTypeSpec::Real &);
+  bool Pre(const parser::IntrinsicTypeSpec::Complex &);
+  bool Pre(const parser::DeclarationTypeSpec::ClassStar &);
+  bool Pre(const parser::DeclarationTypeSpec::TypeStar &);
+  void Post(const parser::DeclarationTypeSpec::Type &);
+  void Post(const parser::DeclarationTypeSpec::Class &);
+  bool Pre(const parser::DeclarationTypeSpec::Record &);
+  bool Pre(const parser::DerivedTypeSpec &);
+  void Post(const parser::TypeParamSpec &);
+  bool Pre(const parser::TypeParamValue &);
 
 protected:
   std::unique_ptr<DeclTypeSpec> declTypeSpec_;
+  std::unique_ptr<DerivedTypeSpec> derivedTypeSpec_;
+  std::unique_ptr<ParamValue> typeParamValue_;
 
 private:
   bool expectDeclTypeSpec_{false};  // should only see decl-type-spec when true
-
-  void MakeIntrinsic(const IntrinsicTypeSpec *intrinsicTypeSpec) {
-    CHECK(expectDeclTypeSpec_ && !declTypeSpec_);
-    declTypeSpec_ = std::make_unique<DeclTypeSpec>(
-        DeclTypeSpec::MakeIntrinsic(intrinsicTypeSpec));
-  }
-
+  void MakeIntrinsic(const IntrinsicTypeSpec &intrinsicTypeSpec);
+  void SetDeclTypeSpec(const DeclTypeSpec &declTypeSpec);
   static KindParamValue GetKindParamValue(
-      const std::optional<parser::KindSelector> &kind) {
-    if (!kind) {
-      return KindParamValue();
-    } else if (std::holds_alternative<parser::ScalarIntConstantExpr>(kind->u)) {
-      const auto &expr = std::get<parser::ScalarIntConstantExpr>(kind->u);
-      const auto &lit =
-          std::get<parser::LiteralConstant>(expr.thing.thing.thing->u);
-      const auto &intlit = std::get<parser::IntLiteralConstant>(lit.u);
-      return KindParamValue(std::get<std::uint64_t>(intlit.t));
-    } else {
-      CHECK(false && "TODO: translate star-size to kind");
-    }
-  }
+      const std::optional<parser::KindSelector> &kind);
 };
 
 // Walk the parse tree and resolve names to symbols.
@@ -124,141 +102,307 @@ public:
   void PushScope(Scope &scope) { scopes_.push(&scope); }
   void PopScope() { scopes_.pop(); }
 
+  // Default action for a parse tree node is to visit children.
+  template<typename T> bool Pre(const T &) { return true; }
+  template<typename T> void Post(const T &) {}
+
+  bool Pre(const parser::TypeDeclarationStmt &);
+  void Post(const parser::TypeDeclarationStmt &);
+  void Post(const parser::EntityDecl &);
+  bool Pre(const parser::PrefixSpec &);
+  void Post(const parser::EndSubroutineStmt &);
+  void Post(const parser::EndFunctionStmt &);
+  bool Pre(const parser::Suffix &);
+  bool Pre(const parser::SubroutineStmt &);
+  void Post(const parser::SubroutineStmt &);
+  bool Pre(const parser::FunctionStmt &);
+  void Post(const parser::FunctionStmt &);
+  void Post(const parser::Program &);
+
+private:
+  // Stack of containing scopes; memory referenced is owned by parent scopes
+  std::stack<Scope *, std::list<Scope *>> scopes_;
+  std::optional<Name> funcResultName_;
+
+  // Common Post() for functions and subroutines.
+  // Create a symbol in the current scope, push a new scope, add the dummies.
+  void PostSubprogram(const Name &name, const std::list<Name> &dummyNames);
+
   // Helpers to make a Symbol in the current scope
-  template<typename D>
-  Symbol &MakeSymbol(const Name &name, D &&details) {
+  template<typename D> Symbol &MakeSymbol(const Name &name, D &&details) {
     return CurrScope().MakeSymbol(name, details);
   }
   template<typename D>
   Symbol &MakeSymbol(const Name &name, const Attrs &attrs, D &&details) {
     return CurrScope().MakeSymbol(name, attrs, details);
   }
+};
 
-  // Default action for a parse tree node is to visit children.
-  template<typename T> bool Pre(const T &x) { return true; }
-  template<typename T> void Post(const T &) {}
-
-  bool Pre(const parser::TypeDeclarationStmt &x) {
-    beginDeclTypeSpec();
-    beginAttrs();
-    return true;
+// AttrsVisitor implementation
+void AttrsVisitor::beginAttrs() {
+  CHECK(!attrs_);
+  attrs_ = std::make_unique<Attrs>();
+}
+Attrs AttrsVisitor::endAttrs() {
+  const auto result = attrs_ ? *attrs_ : Attrs::EMPTY;
+  attrs_.reset();
+  return result;
+}
+void AttrsVisitor::Post(const parser::LanguageBindingSpec &x) {
+  attrs_->Set(Attr::BIND_C);
+  if (x.v) {
+    // TODO: set langBindingName_ from ScalarDefaultCharConstantExpr
   }
-  void Post(const parser::TypeDeclarationStmt &x) {
-    endDeclTypeSpec();
-    endAttrs();
+}
+bool AttrsVisitor::Pre(const parser::AccessSpec &x) {
+  switch (x.v) {
+  case parser::AccessSpec::Kind::Public: attrs_->Set(Attr::PUBLIC); break;
+  case parser::AccessSpec::Kind::Private: attrs_->Set(Attr::PRIVATE); break;
+  default: CRASH_NO_CASE;
+  }
+  return false;
+}
+bool AttrsVisitor::Pre(const parser::IntentSpec &x) {
+  switch (x.v) {
+  case parser::IntentSpec::Intent::In:
+    attrs_->Set(Attr::INTENT_IN);
+    break;
+  case parser::IntentSpec::Intent::Out:
+    attrs_->Set(Attr::INTENT_OUT);
+    break;
+  case parser::IntentSpec::Intent::InOut:
+    attrs_->Set(Attr::INTENT_IN);
+    attrs_->Set(Attr::INTENT_OUT);
+    break;
+  default: CRASH_NO_CASE;
   }
+  return false;
+}
 
-  void Post(const parser::EntityDecl &x) {
-    // TODO: may be under StructureStmt
-    const auto &name = std::get<parser::ObjectName>(x.t);
-    // TODO: optional ArraySpec, CoarraySpec, CharLength, Initialization
-    Symbol &symbol = CurrScope().GetOrMakeSymbol(name.ToString());
-    if (symbol.has<UnknownDetails>()) {
-      symbol.set_details(EntityDetails());
-    } else if (EntityDetails *details = symbol.detailsIf<EntityDetails>()) {
-      if (details->type().has_value()) {
-        std::cerr << "ERROR: symbol already has a type declared: "
-            << name.ToString() << "\n";
-      } else {
-        details->set_type(*declTypeSpec_);
-      }
-    } else {
-      std::cerr
-          << "ERROR: symbol already declared, can't appear in entity-decl: "
-          << name.ToString() << "\n";
-    }
+// DeclTypeSpecVisitor implementation
+void DeclTypeSpecVisitor::beginDeclTypeSpec() {
+  CHECK(!expectDeclTypeSpec_);
+  expectDeclTypeSpec_ = true;
+}
+void DeclTypeSpecVisitor::endDeclTypeSpec() {
+  CHECK(expectDeclTypeSpec_);
+  expectDeclTypeSpec_ = false;
+  declTypeSpec_.reset();
+}
+
+bool DeclTypeSpecVisitor::Pre(const parser::DeclarationTypeSpec::ClassStar &x) {
+  SetDeclTypeSpec(DeclTypeSpec::MakeClassStar());
+  return false;
+}
+bool DeclTypeSpecVisitor::Pre(const parser::DeclarationTypeSpec::TypeStar &x) {
+  SetDeclTypeSpec(DeclTypeSpec::MakeTypeStar());
+  return false;
+}
+bool DeclTypeSpecVisitor::Pre(const parser::DerivedTypeSpec &x) {
+  CHECK(!derivedTypeSpec_);
+  derivedTypeSpec_ =
+      std::make_unique<DerivedTypeSpec>(std::get<parser::Name>(x.t).ToString());
+  return true;
+}
+void DeclTypeSpecVisitor::Post(const parser::TypeParamSpec &x) {
+  if (const auto &keyword = std::get<std::optional<parser::Keyword>>(x.t)) {
+    derivedTypeSpec_->AddParamValue(keyword->v.ToString(), *typeParamValue_);
+  } else {
+    derivedTypeSpec_->AddParamValue(*typeParamValue_);
   }
+  typeParamValue_.reset();
+}
+bool DeclTypeSpecVisitor::Pre(const parser::TypeParamValue &x) {
+  typeParamValue_ = std::make_unique<ParamValue>(
+    std::visit(parser::visitors{
+      [&](const parser::ScalarIntExpr &x) { return Bound{IntExpr{x}}; },
+      [&](const parser::Star &x) { return Bound::ASSUMED; },
+      [&](const parser::TypeParamValue::Deferred &x) { return Bound::DEFERRED; },
+    }, x.u));
+  return false;
+}
 
-  bool Pre(const parser::PrefixSpec &stmt) {
-    // TODO
-    return true;
+void DeclTypeSpecVisitor::Post(const parser::DeclarationTypeSpec::Type &x) {
+  SetDeclTypeSpec(
+      DeclTypeSpec::MakeTypeDerivedType(*derivedTypeSpec_.release()));
+}
+void DeclTypeSpecVisitor::Post(const parser::DeclarationTypeSpec::Class &x) {
+  SetDeclTypeSpec(
+      DeclTypeSpec::MakeClassDerivedType(*derivedTypeSpec_.release()));
+}
+bool DeclTypeSpecVisitor::Pre(const parser::DeclarationTypeSpec::Record &x) {
+  // TODO
+  return true;
+}
+bool DeclTypeSpecVisitor::Pre(const parser::IntegerTypeSpec &x) {
+  MakeIntrinsic(IntegerTypeSpec::Make(GetKindParamValue(x.v)));
+  return false;
+}
+bool DeclTypeSpecVisitor::Pre(const parser::IntrinsicTypeSpec::Logical &x) {
+  MakeIntrinsic(LogicalTypeSpec::Make(GetKindParamValue(x.kind)));
+  return false;
+}
+bool DeclTypeSpecVisitor::Pre(const parser::IntrinsicTypeSpec::Real &x) {
+  MakeIntrinsic(RealTypeSpec::Make(GetKindParamValue(x.kind)));
+  return false;
+}
+bool DeclTypeSpecVisitor::Pre(const parser::IntrinsicTypeSpec::Complex &x) {
+  MakeIntrinsic(ComplexTypeSpec::Make(GetKindParamValue(x.kind)));
+  return false;
+}
+void DeclTypeSpecVisitor::MakeIntrinsic(
+    const IntrinsicTypeSpec &intrinsicTypeSpec) {
+  SetDeclTypeSpec(DeclTypeSpec::MakeIntrinsic(intrinsicTypeSpec));
+}
+// Check that we're expecting to see a DeclTypeSpec (and haven't seen one yet)
+// and save it in declTypeSpec_.
+void DeclTypeSpecVisitor::SetDeclTypeSpec(const DeclTypeSpec &declTypeSpec) {
+  CHECK(expectDeclTypeSpec_ && !declTypeSpec_);
+  declTypeSpec_ = std::make_unique<DeclTypeSpec>(declTypeSpec);
+}
+
+KindParamValue DeclTypeSpecVisitor::GetKindParamValue(
+    const std::optional<parser::KindSelector> &kind) {
+  if (!kind) {
+    return KindParamValue();
+  } else if (const auto *expr =
+                 std::get_if<parser::ScalarIntConstantExpr>(&kind->u)) {
+    const auto &lit =
+        std::get<parser::LiteralConstant>(expr->thing.thing.thing->u);
+    const auto &intlit = std::get<parser::IntLiteralConstant>(lit.u);
+    return KindParamValue(std::get<std::uint64_t>(intlit.t));
+  } else {
+    CHECK(!"TODO: translate star-size to kind");
   }
-  void Post(const parser::EndFunctionStmt &subp) {
-    std::cout << "End of function scope\n";
-    std::cout << CurrScope();
-    PopScope();
+}
+
+
+// ResolveNamesVisitor implementation
+
+void ResolveNamesVisitor::Post(const parser::EntityDecl &x) {
+  // TODO: may be under StructureStmt
+  const auto &name = std::get<parser::ObjectName>(x.t);
+  // TODO: optional ArraySpec, CoarraySpec, CharLength, Initialization
+  Symbol &symbol = CurrScope().GetOrMakeSymbol(name.ToString());
+  symbol.attrs().Add(*attrs_);  //TODO: check attribute consistency
+  if (symbol.has<UnknownDetails>()) {
+    symbol.set_details(EntityDetails());
   }
-  bool Pre(const parser::Suffix &suffix) {
-    if (suffix.resultName.has_value()) {
-      funcResultName_ =
-          std::make_optional(suffix.resultName->ToString());
+  if (EntityDetails *details = symbol.detailsIf<EntityDetails>()) {
+    if (details->type().has_value()) {
+      std::cerr << "ERROR: symbol already has a type declared: "
+          << name.ToString() << "\n";
+    } else {
+      details->set_type(*declTypeSpec_);
     }
-    return true;
+  } else {
+    std::cerr
+        << "ERROR: symbol already declared, can't appear in entity-decl: "
+        << name.ToString() << "\n";
   }
+}
 
-  bool Pre(const parser::SubroutineStmt &stmt) {
-    beginAttrs();
-    return true;
-  }
+bool ResolveNamesVisitor::Pre(const parser::TypeDeclarationStmt &x) {
+  beginDeclTypeSpec();
+  beginAttrs();
+  return true;
+}
 
-  // Common Post() for functions and subroutines.
-  void PostSubprogram(
-      const Name &name, const std::list<Name> &dummyNames) {
-    const auto attrs = endAttrs();
-    MakeSymbol(name, attrs, SubprogramDetails(dummyNames));
-    Scope &subpScope = CurrScope().MakeScope(Scope::Kind::Subprogram);
-    PushScope(subpScope);
-    for (const auto &dummyName : dummyNames) {
-      MakeSymbol(dummyName, EntityDetails(true));
-    }
+void ResolveNamesVisitor::Post(const parser::TypeDeclarationStmt &x) {
+  endDeclTypeSpec();
+  endAttrs();
+}
+
+bool ResolveNamesVisitor::Pre(const parser::PrefixSpec &stmt) {
+  return true;  // TODO
+}
+
+void ResolveNamesVisitor::Post(const parser::EndSubroutineStmt &subp) {
+  std::cout << "End of subroutine scope\n";
+  std::cout << CurrScope();
+  PopScope();
+}
+
+void ResolveNamesVisitor::Post(const parser::EndFunctionStmt &subp) {
+  std::cout << "End of function scope\n";
+  std::cout << CurrScope();
+  PopScope();
+}
+
+bool ResolveNamesVisitor::Pre(const parser::Suffix &suffix) {
+  if (suffix.resultName.has_value()) {
+    funcResultName_ = std::make_optional(suffix.resultName->ToString());
   }
+  return true;
+}
 
-  void Post(const parser::SubroutineStmt &stmt) {
-    Name subrName = std::get<parser::Name>(stmt.t).ToString();
-    std::list<Name> dummyNames;
-    const auto &dummyArgs = std::get<std::list<parser::DummyArg>>(stmt.t);
-    for (const parser::DummyArg &dummyArg : dummyArgs) {
-      const parser::Name *dummyName = std::get_if<parser::Name>(&dummyArg.u);
-      CHECK(dummyName != nullptr && "TODO: alternate return indicator");
-      dummyNames.push_back(dummyName->ToString());
-    }
-    PostSubprogram(subrName, dummyNames);
-    MakeSymbol(subrName, SubprogramDetails(dummyNames));
+bool ResolveNamesVisitor::Pre(const parser::SubroutineStmt &stmt) {
+  beginAttrs();
+  return true;
+}
+
+void ResolveNamesVisitor::Post(const parser::SubroutineStmt &stmt) {
+  Name subrName = std::get<parser::Name>(stmt.t).ToString();
+  std::list<Name> dummyNames;
+  const auto &dummyArgs = std::get<std::list<parser::DummyArg>>(stmt.t);
+  for (const parser::DummyArg &dummyArg : dummyArgs) {
+    const parser::Name *dummyName = std::get_if<parser::Name>(&dummyArg.u);
+    CHECK(dummyName != nullptr && "TODO: alternate return indicator");
+    dummyNames.push_back(dummyName->ToString());
   }
+  PostSubprogram(subrName, dummyNames);
+  MakeSymbol(subrName, SubprogramDetails(dummyNames));
+}
 
-  bool Pre(const parser::FunctionStmt &stmt) {
-    beginAttrs();
-    beginDeclTypeSpec();
-    CHECK(!funcResultName_);
-    return true;
+bool ResolveNamesVisitor::Pre(const parser::FunctionStmt &stmt) {
+  beginAttrs();
+  beginDeclTypeSpec();
+  CHECK(!funcResultName_);
+  return true;
+}
+
+void ResolveNamesVisitor::Post(const parser::FunctionStmt &stmt) {
+  Name funcName = std::get<parser::Name>(stmt.t).ToString();
+  std::list<Name> dummyNames;
+  for (const auto &dummy : std::get<std::list<parser::Name>>(stmt.t)) {
+    dummyNames.push_back(dummy.ToString());
   }
-  // TODO: MakeSymbol function
-  void Post(const parser::FunctionStmt &stmt) {
-    Name funcName = std::get<parser::Name>(stmt.t).ToString();
-    std::list<Name> dummyNames;
-    for (const auto &dummy : std::get<std::list<parser::Name>>(stmt.t)) {
-      dummyNames.push_back(dummy.ToString());
-    }
-    PostSubprogram(funcName, dummyNames);
-    // add function result to function scope
-    EntityDetails funcResultDetails;
-    if (declTypeSpec_) {
-      funcResultDetails.set_type(*declTypeSpec_);
-    }
-    const auto &resultName = funcResultName_ ? *funcResultName_ : funcName;
-    MakeSymbol(resultName, funcResultDetails);
-    if (resultName != funcName) {
-      // add symbol for function to its scope; name can't be reused
-      MakeSymbol(funcName, SubprogramDetails(dummyNames, funcResultName_));
-    }
-    endDeclTypeSpec();
-    funcResultName_ = std::nullopt;
+  PostSubprogram(funcName, dummyNames);
+  // add function result to function scope
+  EntityDetails funcResultDetails;
+  if (declTypeSpec_) {
+    funcResultDetails.set_type(*declTypeSpec_);
   }
+  const auto &resultName = funcResultName_ ? *funcResultName_ : funcName;
+  MakeSymbol(resultName, funcResultDetails);
+  if (resultName != funcName) {
+    // add symbol for function to its scope; name can't be reused
+    MakeSymbol(funcName, SubprogramDetails(dummyNames, funcResultName_));
+  }
+  endDeclTypeSpec();
+  funcResultName_ = std::nullopt;
+}
 
-  void Post(const parser::Program &) {
-    // ensure that all temps were deallocated
-    CHECK(!attrs_);
-    CHECK(!declTypeSpec_);
+void ResolveNamesVisitor::PostSubprogram(const Name &name, const std::list<Name> &dummyNames) {
+  const auto attrs = endAttrs();
+  MakeSymbol(name, attrs, SubprogramDetails(dummyNames));
+  Scope &subpScope = CurrScope().MakeScope(Scope::Kind::Subprogram);
+  PushScope(subpScope);
+  for (const auto &dummyName : dummyNames) {
+    MakeSymbol(dummyName, EntityDetails(true));
   }
+}
+
+void ResolveNamesVisitor::Post(const parser::Program &) {
+  // ensure that all temps were deallocated
+  CHECK(!attrs_);
+  CHECK(!declTypeSpec_);
+}
 
-private:
-  // Stack of containing scopes; memory referenced is owned by parent scopes
-  std::stack<Scope *, std::list<Scope *>> scopes_;
-  std::optional<Name> funcResultName_;
-};
 
 void ResolveNames(const parser::Program &program) {
   ResolveNamesVisitor visitor;
   parser::Walk(program, visitor);
 }
+
 }  // namespace Fortran::semantics
index 4be7907..3742527 100644 (file)
@@ -68,6 +68,7 @@ public:
     : owner_{owner}, name_{name}, attrs_{attrs}, details_{std::move(details)} {}
   const Scope &owner() const { return owner_; }
   const Name &name() const { return name_; }
+  Attrs &attrs() { return attrs_; }
   const Attrs &attrs() const { return attrs_; }
 
   // Does symbol have this type of details?
@@ -92,15 +93,15 @@ public:
 
   // Assign the details of the symbol from one of the variants.
   // Only allowed if unknown.
-  void set_details(const Details &details) {
+  void set_details(Details &&details) {
     CHECK(has<UnknownDetails>());
-    details_ = details;
-  };
+    details_.swap(details);
+  }
 
 private:
   const Scope &owner_;
   const Name name_;
-  const Attrs attrs_;
+  Attrs attrs_;
   Details details_;
   friend std::ostream &operator<<(std::ostream &, const Symbol &);
 };
index a0bf115..790a8a3 100644 (file)
@@ -6,32 +6,13 @@
 namespace Fortran {
 namespace semantics {
 
-// Check that values specified for param defs are valid: they must match the
-// names of the params and any def that doesn't have a default value must have a
-// value.
-template<typename V>
-static void checkParams(
-    std::string kindOrLen, TypeParamDefs defs, std::map<Name, V> values) {
-  std::set<Name> validNames{};
-  for (const TypeParamDef &def : defs) {
-    Name name = def.name();
-    validNames.insert(name);
-    if (!def.defaultValue() && values.find(name) == values.end()) {
-      parser::die("no value or default value for %s parameter '%s'",
-          kindOrLen.c_str(), name.c_str());
-    }
-  }
-  for (const auto &pair : values) {
-    Name name = pair.first;
-    if (validNames.find(name) == validNames.end()) {
-      parser::die("invalid %s parameter '%s'", kindOrLen.c_str(), name.c_str());
-    }
-  }
-}
 
 std::ostream &operator<<(std::ostream &o, const IntExpr &x) {
   return x.Output(o);
 }
+std::ostream &operator<<(std::ostream &o, const IntConst &x) {
+  return o << x.value_;
+}
 
 std::unordered_map<std::uint64_t, IntConst> IntConst::cache;
 
@@ -47,36 +28,36 @@ const IntConst &IntConst::Make(std::uint64_t value) {
   return it->second;
 }
 
-const LogicalTypeSpec *LogicalTypeSpec::Make() { return &helper.Make(); }
-const LogicalTypeSpec *LogicalTypeSpec::Make(KindParamValue kind) {
-  return &helper.Make(kind);
+const LogicalTypeSpec &LogicalTypeSpec::Make() { return helper.Make(); }
+const LogicalTypeSpec &LogicalTypeSpec::Make(KindParamValue kind) {
+  return helper.Make(kind);
 }
 KindedTypeHelper<LogicalTypeSpec> LogicalTypeSpec::helper{"LOGICAL", 0};
 std::ostream &operator<<(std::ostream &o, const LogicalTypeSpec &x) {
   return LogicalTypeSpec::helper.Output(o, x);
 }
 
-const IntegerTypeSpec *IntegerTypeSpec::Make() { return &helper.Make(); }
-const IntegerTypeSpec *IntegerTypeSpec::Make(KindParamValue kind) {
-  return &helper.Make(kind);
+const IntegerTypeSpec &IntegerTypeSpec::Make() { return helper.Make(); }
+const IntegerTypeSpec &IntegerTypeSpec::Make(KindParamValue kind) {
+  return helper.Make(kind);
 }
 KindedTypeHelper<IntegerTypeSpec> IntegerTypeSpec::helper{"INTEGER", 0};
 std::ostream &operator<<(std::ostream &o, const IntegerTypeSpec &x) {
   return IntegerTypeSpec::helper.Output(o, x);
 }
 
-const RealTypeSpec *RealTypeSpec::Make() { return &helper.Make(); }
-const RealTypeSpec *RealTypeSpec::Make(KindParamValue kind) {
-  return &helper.Make(kind);
+const RealTypeSpec &RealTypeSpec::Make() { return helper.Make(); }
+const RealTypeSpec &RealTypeSpec::Make(KindParamValue kind) {
+  return helper.Make(kind);
 }
 KindedTypeHelper<RealTypeSpec> RealTypeSpec::helper{"REAL", 0};
 std::ostream &operator<<(std::ostream &o, const RealTypeSpec &x) {
   return RealTypeSpec::helper.Output(o, x);
 }
 
-const ComplexTypeSpec *ComplexTypeSpec::Make() { return &helper.Make(); }
-const ComplexTypeSpec *ComplexTypeSpec::Make(KindParamValue kind) {
-  return &helper.Make(kind);
+const ComplexTypeSpec &ComplexTypeSpec::Make() { return helper.Make(); }
+const ComplexTypeSpec &ComplexTypeSpec::Make(KindParamValue kind) {
+  return helper.Make(kind);
 }
 KindedTypeHelper<ComplexTypeSpec> ComplexTypeSpec::helper{"COMPLEX", 0};
 std::ostream &operator<<(std::ostream &o, const ComplexTypeSpec &x) {
@@ -136,31 +117,19 @@ std::ostream &operator<<(std::ostream &o, const DerivedTypeDef &x) {
   return o << "END TYPE";
 }
 
-DerivedTypeSpec::DerivedTypeSpec(DerivedTypeDef def,
-    const KindParamValues &kindParamValues,
-    const LenParamValues &lenParamValues)
-  : def_{def}, kindParamValues_{kindParamValues}, lenParamValues_{
-                                                      lenParamValues} {
-  checkParams("kind", def.kindParams(), kindParamValues);
-  checkParams("len", def.lenParams(), lenParamValues);
-}
-
 std::ostream &operator<<(std::ostream &o, const DerivedTypeSpec &x) {
-  o << "TYPE(" << x.def_.name();
-  if (x.kindParamValues_.size() > 0 || x.lenParamValues_.size() > 0) {
+  o << "TYPE(" << x.name_;
+  if (!x.paramValues_.empty()) {
     o << '(';
     int n = 0;
-    for (const auto &pair : x.kindParamValues_) {
+    for (const auto &paramValue : x.paramValues_) {
       if (n++) {
         o << ", ";
       }
-      o << pair.first << '=' << pair.second;
-    }
-    for (const auto &pair : x.lenParamValues_) {
-      if (n++) {
-        o << ", ";
+      if (paramValue.first) {
+        o << *paramValue.first << '=';
       }
-      o << pair.first << '=' << pair.second;
+      o << paramValue.second;
     }
     o << ')';
   }
@@ -234,12 +203,33 @@ DataComponentDef::DataComponentDef(const DeclTypeSpec &type, const Name &name,
   }
 }
 
+// All instances of IntrinsicTypeSpec live in caches and are never deleted,
+// so the pointer to intrinsicTypeSpec will always be valid
+// derivedTypeSpec_ is dynamically allocated and owned by the DeclTypeSpec
+DeclTypeSpec::DeclTypeSpec(Category category, const DerivedTypeSpec &derivedTypeSpec)
+  : category_{category}, intrinsicTypeSpec_{nullptr},
+    derivedTypeSpec_{new DerivedTypeSpec(derivedTypeSpec)} {
+  CHECK(category == TypeDerived || category == ClassDerived);
+}
+DeclTypeSpec::DeclTypeSpec(const DeclTypeSpec &that)
+  : category_{that.category_}, intrinsicTypeSpec_{that.intrinsicTypeSpec_} {
+  if (category_ == TypeDerived || category_ == ClassDerived) {
+    derivedTypeSpec_ = new DerivedTypeSpec(*that.derivedTypeSpec_);
+  }
+}
+DeclTypeSpec::~DeclTypeSpec() {
+  if (category_ == TypeDerived || category_ == ClassDerived) {
+    delete derivedTypeSpec_;
+    derivedTypeSpec_ = nullptr;
+  }
+}
+
 std::ostream &operator<<(std::ostream &o, const DeclTypeSpec &x) {
   // TODO: need CLASS(...) instead of TYPE() for ClassDerived
   switch (x.category_) {
-  case DeclTypeSpec::Intrinsic: return x.intrinsicTypeSpec_->Output(o);
-  case DeclTypeSpec::TypeDerived: return o << *x.derivedTypeSpec_;
-  case DeclTypeSpec::ClassDerived: return o << *x.derivedTypeSpec_;
+  case DeclTypeSpec::Intrinsic: return x.intrinsicTypeSpec().Output(o);
+  case DeclTypeSpec::TypeDerived: return o << x.derivedTypeSpec();
+  case DeclTypeSpec::ClassDerived: return o << x.derivedTypeSpec();
   case DeclTypeSpec::TypeStar: return o << "TYPE(*)";
   case DeclTypeSpec::ClassStar: return o << "CLASS(*)";
   default: CRASH_NO_CASE;
@@ -322,98 +312,3 @@ DerivedTypeDefBuilder &DerivedTypeDefBuilder::sequence(bool x) {
 
 }  // namespace semantics
 }  // namespace Fortran
-
-using namespace Fortran::semantics;
-
-void testTypeSpec() {
-  const LogicalTypeSpec *l1 = LogicalTypeSpec::Make();
-  const LogicalTypeSpec *l2 = LogicalTypeSpec::Make(2);
-  std::cout << *l1 << "\n";
-  std::cout << *l2 << "\n";
-  const RealTypeSpec *r1 = RealTypeSpec::Make();
-  const RealTypeSpec *r2 = RealTypeSpec::Make(2);
-  std::cout << *r1 << "\n";
-  std::cout << *r2 << "\n";
-  const CharacterTypeSpec c1{LenParamValue::DEFERRED, 1};
-  std::cout << c1 << "\n";
-  const CharacterTypeSpec c2{IntConst::Make(10)};
-  std::cout << c2 << "\n";
-
-  const IntegerTypeSpec *i1 = IntegerTypeSpec::Make();
-  const IntegerTypeSpec *i2 = IntegerTypeSpec::Make(2);
-  TypeParamDef lenParam{"my_len", *i2};
-  TypeParamDef kindParam{"my_kind", *i1};
-
-  DerivedTypeDef def1{DerivedTypeDefBuilder("my_name")
-                          .attrs({Attr::PRIVATE, Attr::BIND_C})
-                          .lenParam(lenParam)
-                          .kindParam(kindParam)
-                          .sequence()};
-  // DerivedTypeDef def1{"my_name", {Attr::PRIVATE, Attr::BIND_C},
-  //    TypeParamDefs{lenParam}, TypeParamDefs{kindParam}, false, true};
-
-  LenParamValues lenParamValues{
-      LenParamValues::value_type{"my_len", LenParamValue::ASSUMED},
-  };
-  KindParamValues kindParamValues{
-      KindParamValues::value_type{"my_kind", KindParamValue{123}},
-  };
-  // DerivedTypeSpec dt1{def1, kindParamValues, lenParamValues};
-
-  // DerivedTypeSpec dt1{DerivedTypeSpec::Builder{"my_name2"}
-  //  .lenParamValue("my_len", LenParamValue::ASSUMED)
-  //  .attrs({Attr::BIND_C}).lenParam(lenParam)};
-  // std::cout << dt1 << "\n";
-}
-
-void testShapeSpec() {
-  const IntConst &ten{IntConst::Make(10)};
-  const ShapeSpec s1{ShapeSpec::MakeExplicit(ten)};
-  std::cout << "explicit-shape-spec: " << s1 << "\n";
-  ShapeSpec s2{ShapeSpec::MakeExplicit(IntConst::Make(2), IntConst::Make(8))};
-  std::cout << "explicit-shape-spec: " << s2 << "\n";
-
-  ShapeSpec s3{ShapeSpec::MakeAssumed()};
-  std::cout << "assumed-shape-spec:  " << s3 << "\n";
-  ShapeSpec s4{ShapeSpec::MakeAssumed(IntConst::Make(2))};
-  std::cout << "assumed-shape-spec:  " << s4 << "\n";
-
-  ShapeSpec s5{ShapeSpec::MakeDeferred()};
-  std::cout << "deferred-shape-spec: " << s5 << "\n";
-
-  ShapeSpec s6{ShapeSpec::MakeImplied(IntConst::Make(2))};
-  std::cout << "implied-shape-spec:  " << s6 << "\n";
-
-  ShapeSpec s7{ShapeSpec::MakeAssumedRank()};
-  std::cout << "assumed-rank-spec:  " << s7 << "\n";
-}
-
-void testDataComponentDef() {
-  DataComponentDef def1{
-      DeclTypeSpec::MakeClassStar(), "foo", Attrs{Attr::PUBLIC}};
-  std::cout << "data-component-def: " << def1 << "\n";
-  DataComponentDef def2{DeclTypeSpec::MakeTypeStar(), "foo", Attrs{},
-      ComponentArraySpec{ShapeSpec::MakeExplicit(IntConst::Make(10))}};
-  std::cout << "data-component-def: " << def2 << "\n";
-}
-
-void testProcComponentDef() {
-  ProcDecl decl{"foo"};
-  ProcComponentDef def1{decl, Attrs{Attr::POINTER, Attr::PUBLIC, Attr::NOPASS}};
-  std::cout << "proc-component-def: " << def1;
-  ProcComponentDef def2{decl, Attrs{Attr::POINTER}, Name{"my_interface"}};
-  std::cout << "proc-component-def: " << def2;
-  ProcComponentDef def3{
-      decl, Attrs{Attr::POINTER}, DeclTypeSpec::MakeTypeStar()};
-  std::cout << "proc-component-def: " << def3;
-}
-
-#if 0
-int main() {
-  testTypeSpec();
-  //testShapeSpec();
-  //testProcComponentDef();
-  //testDataComponentDef();
-  return 0;
-}
-#endif
index db91388..f3d717d 100644 (file)
@@ -2,6 +2,7 @@
 #define FORTRAN_TYPE_H_
 
 #include "../parser/idioms.h"
+#include "../parser/parse-tree.h"
 #include "attr.h"
 #include <list>
 #include <map>
@@ -42,19 +43,22 @@ using Name = std::string;
 // TODO
 class IntExpr {
 public:
-  virtual const IntExpr *Clone() const { return new IntExpr{*this}; }
+  static IntExpr MakeConst(std::uint64_t value) {
+    return IntExpr(); // TODO
+  }
+  IntExpr() {}
+  IntExpr(const parser::ScalarIntExpr &) { /*TODO*/ }
   virtual std::ostream &Output(std::ostream &o) const { return o << "IntExpr"; }
 };
 
 // TODO
-class IntConst : public IntExpr {
+class IntConst {
 public:
   static const IntConst &Make(std::uint64_t value);
-  const IntExpr *Clone() const override { return &Make(value_); }
   bool operator==(const IntConst &x) const { return value_ == x.value_; }
   bool operator!=(const IntConst &x) const { return !operator==(x); }
   bool operator<(const IntConst &x) const { return value_ < x.value_; }
-  std::ostream &Output(std::ostream &o) const override {
+  std::ostream &Output(std::ostream &o) const {
     return o << this->value_;
   }
 
@@ -62,6 +66,7 @@ private:
   static std::unordered_map<std::uint64_t, IntConst> cache;
   IntConst(std::uint64_t value) : value_{value} {}
   const std::uint64_t value_;
+  friend std::ostream &operator<<(std::ostream &, const IntConst &);
 };
 
 // The value of a kind type parameter
@@ -82,17 +87,20 @@ class Bound {
 public:
   static const Bound ASSUMED;
   static const Bound DEFERRED;
-  Bound(const IntExpr &expr) : category_{Explicit}, expr_{expr.Clone()} {}
+  Bound(const IntExpr &expr) : category_{Explicit}, expr_{expr} {}
   bool isExplicit() const { return category_ == Explicit; }
   bool isAssumed() const { return category_ == Assumed; }
   bool isDeferred() const { return category_ == Deferred; }
-  const IntExpr &getExplicit() const { return *expr_; }
+  const IntExpr &getExplicit() const {
+    CHECK(isExplicit());
+    return *expr_;
+  }
 
 private:
   enum Category { Explicit, Deferred, Assumed };
-  Bound(Category category) : category_{category}, expr_{&IntConst::Make(0)} {}
+  Bound(Category category) : category_{category}, expr_{std::nullopt} {}
   const Category category_;
-  const IntExpr *const expr_;
+  const std::optional<IntExpr> expr_;
   friend std::ostream &operator<<(std::ostream &, const Bound &);
 };
 
@@ -104,44 +112,46 @@ class DerivedTypeSpec;
 class DeclTypeSpec {
 public:
   // intrinsic-type-spec or TYPE(intrinsic-type-spec)
-  static DeclTypeSpec MakeIntrinsic(
-      const IntrinsicTypeSpec *intrinsicTypeSpec) {
-    return DeclTypeSpec{Intrinsic, intrinsicTypeSpec};
+  static DeclTypeSpec MakeIntrinsic(const IntrinsicTypeSpec &typeSpec) {
+    return DeclTypeSpec{typeSpec};
   }
   // TYPE(derived-type-spec)
-  static DeclTypeSpec MakeTypeDerivedType(
-      const DerivedTypeSpec *derivedTypeSpec) {
-    return DeclTypeSpec{TypeDerived, nullptr, derivedTypeSpec};
+  static DeclTypeSpec MakeTypeDerivedType(const DerivedTypeSpec &typeSpec) {
+    return DeclTypeSpec{TypeDerived, typeSpec};
   }
   // CLASS(derived-type-spec)
-  static DeclTypeSpec MakeClassDerivedType(
-      const DerivedTypeSpec *derivedTypeSpec) {
-    return DeclTypeSpec{ClassDerived, nullptr, derivedTypeSpec};
+  static DeclTypeSpec MakeClassDerivedType(const DerivedTypeSpec &typeSpec) {
+    return DeclTypeSpec{ClassDerived, typeSpec};
   }
   // TYPE(*)
   static DeclTypeSpec MakeTypeStar() { return DeclTypeSpec{TypeStar}; }
   // CLASS(*)
   static DeclTypeSpec MakeClassStar() { return DeclTypeSpec{ClassStar}; }
 
+  DeclTypeSpec(const DeclTypeSpec &that);
+  ~DeclTypeSpec();
   enum Category { Intrinsic, TypeDerived, ClassDerived, TypeStar, ClassStar };
   Category category() const { return category_; }
-  const IntrinsicTypeSpec *intrinsicTypeSpec() const {
-    return intrinsicTypeSpec_;
+  const IntrinsicTypeSpec &intrinsicTypeSpec() const {
+    return *intrinsicTypeSpec_;
   }
-  const DerivedTypeSpec *derivedTypeSpec() const { return derivedTypeSpec_; }
+  const DerivedTypeSpec &derivedTypeSpec() const { return *derivedTypeSpec_; }
 
 private:
-  DeclTypeSpec(Category category,
-      const IntrinsicTypeSpec *intrinsicTypeSpec = nullptr,
-      const DerivedTypeSpec *derivedTypeSpec = nullptr)
-    : category_{category}, intrinsicTypeSpec_{intrinsicTypeSpec},
-      derivedTypeSpec_{derivedTypeSpec} {}
+  DeclTypeSpec(Category category) : category_{category} {
+    CHECK(category == TypeStar || category == ClassStar);
+  }
+  DeclTypeSpec(Category category, const DerivedTypeSpec &typeSpec);
+  DeclTypeSpec(const IntrinsicTypeSpec &intrinsicTypeSpec)
+    : category_{Intrinsic}, intrinsicTypeSpec_{&intrinsicTypeSpec} {}
+
   Category category_;
-  const IntrinsicTypeSpec *intrinsicTypeSpec_;
-  const DerivedTypeSpec *derivedTypeSpec_;
+  const IntrinsicTypeSpec *intrinsicTypeSpec_{nullptr};
+  const DerivedTypeSpec *derivedTypeSpec_{nullptr};
   friend std::ostream &operator<<(std::ostream &, const DeclTypeSpec &);
 };
 
+
 // Root of the *TypeSpec hierarchy
 class TypeSpec {
 public:
@@ -194,8 +204,8 @@ private:
 // One unique instance of LogicalTypeSpec for each kind.
 class LogicalTypeSpec : public IntrinsicTypeSpec {
 public:
-  static const LogicalTypeSpec *Make();
-  static const LogicalTypeSpec *Make(KindParamValue kind);
+  static const LogicalTypeSpec &Make();
+  static const LogicalTypeSpec &Make(KindParamValue kind);
   std::ostream &Output(std::ostream &o) const override { return o << *this; }
 
 private:
@@ -208,8 +218,8 @@ private:
 // One unique instance of IntegerTypeSpec for each kind.
 class IntegerTypeSpec : public NumericTypeSpec {
 public:
-  static const IntegerTypeSpec *Make();
-  static const IntegerTypeSpec *Make(KindParamValue kind);
+  static const IntegerTypeSpec &Make();
+  static const IntegerTypeSpec &Make(KindParamValue kind);
   std::ostream &Output(std::ostream &o) const override { return o << *this; }
 
 private:
@@ -222,8 +232,8 @@ private:
 // One unique instance of RealTypeSpec for each kind.
 class RealTypeSpec : public NumericTypeSpec {
 public:
-  static const RealTypeSpec *Make();
-  static const RealTypeSpec *Make(KindParamValue kind);
+  static const RealTypeSpec &Make();
+  static const RealTypeSpec &Make(KindParamValue kind);
   std::ostream &Output(std::ostream &o) const override { return o << *this; }
 
 private:
@@ -236,8 +246,8 @@ private:
 // One unique instance of ComplexTypeSpec for each kind.
 class ComplexTypeSpec : public NumericTypeSpec {
 public:
-  static const ComplexTypeSpec *Make();
-  static const ComplexTypeSpec *Make(KindParamValue kind);
+  static const ComplexTypeSpec &Make();
+  static const ComplexTypeSpec &Make(KindParamValue kind);
   std::ostream &Output(std::ostream &o) const override { return o << *this; }
 
 private:
@@ -285,10 +295,10 @@ public:
   }
   // 1:ub
   static const ShapeSpec MakeExplicit(const Bound &ub) {
-    return MakeExplicit(IntConst::Make(1), ub);
+    return MakeExplicit(IntExpr::MakeConst(1), ub);
   }
   // 1: or lb:
-  static ShapeSpec MakeAssumed(const Bound &lb = IntConst::Make(1)) {
+  static ShapeSpec MakeAssumed(const Bound &lb = IntExpr::MakeConst(1)) {
     return ShapeSpec(lb, Bound::DEFERRED);
   }
   // :
@@ -296,7 +306,7 @@ public:
     return ShapeSpec(Bound::DEFERRED, Bound::DEFERRED);
   }
   // 1:* or lb:*
-  static ShapeSpec MakeImplied(const Bound &lb = IntConst::Make(1)) {
+  static ShapeSpec MakeImplied(const Bound &lb = IntExpr::MakeConst(1)) {
     return ShapeSpec(lb, Bound::ASSUMED);
   }
   // ..
@@ -421,20 +431,26 @@ private:
   friend class DerivedTypeDef;
 };
 
-using KindParamValues = std::map<Name, KindParamValue>;
-using LenParamValues = std::map<Name, LenParamValue>;
+using ParamValue = LenParamValue;
 
 // Instantiation of a DerivedTypeDef with kind and len parameter values
 class DerivedTypeSpec : public TypeSpec {
 public:
   std::ostream &Output(std::ostream &o) const override { return o << *this; }
+  DerivedTypeSpec(const Name &name) : name_{name} {}
+  virtual ~DerivedTypeSpec() = default;
+  DerivedTypeSpec &AddParamValue(const ParamValue &value) {
+    paramValues_.push_back(std::make_pair(std::nullopt, value));
+    return *this;
+  }
+  DerivedTypeSpec &AddParamValue(const Name &name, const ParamValue &value) {
+    paramValues_.push_back(std::make_pair(name, value));
+    return *this;
+  }
 
 private:
-  const DerivedTypeDef def_;
-  const KindParamValues kindParamValues_;
-  const LenParamValues lenParamValues_;
-  DerivedTypeSpec(DerivedTypeDef def, const KindParamValues &kindParamValues,
-      const LenParamValues &lenParamValues);
+  const Name name_;
+  std::list<std::pair<std::optional<Name>, ParamValue>> paramValues_;
   friend std::ostream &operator<<(std::ostream &, const DerivedTypeSpec &);
 };