[flang-commits] [flang] 841f699 - [flang][fir][NFC] Move remaining types to TableGen type definition

via flang-commits flang-commits at lists.llvm.org
Wed Feb 24 17:23:40 PST 2021


Author: Valentin Clement
Date: 2021-02-24T20:23:31-05:00
New Revision: 841f6995cd33b8891655b2aeb78deca548362c23

URL: https://github.com/llvm/llvm-project/commit/841f6995cd33b8891655b2aeb78deca548362c23
DIFF: https://github.com/llvm/llvm-project/commit/841f6995cd33b8891655b2aeb78deca548362c23.diff

LOG: [flang][fir][NFC] Move remaining types to TableGen type definition

Move the remaing of FIR types to TableGen type definition. This follow suggestion in D96422.

Reviewed By: schweitz, jeanPerier, rriddle

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

Added: 
    

Modified: 
    flang/include/flang/Optimizer/Dialect/FIROps.td
    flang/include/flang/Optimizer/Dialect/FIRType.h
    flang/include/flang/Optimizer/Dialect/FIRTypes.td
    flang/lib/Optimizer/Dialect/FIRType.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 40f0bb8e9d8e..fed8b8d770fa 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -22,94 +22,6 @@ include "mlir/Interfaces/SideEffectInterfaces.td"
 
 include "flang/Optimizer/Dialect/FIRTypes.td"
 
-// Types and predicates
-
-def fir_Type : Type<CPred<"fir::isa_fir_or_std_type($_self)">,
-    "FIR dialect type">;
-
-// Fortran intrinsic types
-def fir_IntegerType : Type<CPred<"$_self.isa<fir::IntegerType>()">,
-    "FIR integer type">;
-def fir_LogicalType : Type<CPred<"$_self.isa<fir::LogicalType>()">,
-    "FIR logical type">;
-def fir_RealType : Type<CPred<"$_self.isa<fir::RealType>()">,
-    "FIR real type">;
-def fir_VectorType : Type<CPred<"$_self.isa<fir::VectorType>()">,
-    "FIR vector type">;
-
-// Generalized FIR and standard dialect types representing intrinsic types
-def AnyIntegerLike : TypeConstraint<Or<[SignlessIntegerLike.predicate,
-    fir_IntegerType.predicate]>, "any integer">;
-def AnyLogicalLike : TypeConstraint<Or<[BoolLike.predicate,
-    fir_LogicalType.predicate]>, "any logical">;
-def AnyRealLike : TypeConstraint<Or<[FloatLike.predicate,
-    fir_RealType.predicate]>, "any real">;
-def AnyIntegerType : Type<AnyIntegerLike.predicate, "any integer">;
-
-// Fortran derived (user defined) type
-def fir_RecordType : Type<CPred<"$_self.isa<fir::RecordType>()">,
-    "FIR derived type">;
-
-// Fortran array attribute
-def fir_SequenceType : Type<CPred<"$_self.isa<fir::SequenceType>()">,
-    "array type">;
-
-// Composable types
-def AnyCompositeLike : TypeConstraint<Or<[fir_RecordType.predicate,
-    fir_SequenceType.predicate, fir_ComplexType.predicate,
-    fir_VectorType.predicate, IsTupleTypePred]>, "any composite">;
-
-// Reference to an entity type
-def fir_ReferenceType : Type<CPred<"$_self.isa<fir::ReferenceType>()">,
-    "reference type">;
-
-// Reference to an ALLOCATABLE attribute type
-def fir_HeapType : Type<CPred<"$_self.isa<fir::HeapType>()">,
-    "allocatable type">;
-
-// Reference to a POINTER attribute type
-def fir_PointerType : Type<CPred<"$_self.isa<fir::PointerType>()">,
-    "pointer type">;
-
-// Reference types
-def AnyReferenceLike : TypeConstraint<Or<[fir_ReferenceType.predicate,
-    fir_HeapType.predicate, fir_PointerType.predicate]>, "any reference">;
-
-def AnyBoxLike : TypeConstraint<Or<[fir_BoxType.predicate,
-    fir_BoxCharType.predicate, fir_BoxProcType.predicate]>, "any box">;
-
-def AnyRefOrBox : TypeConstraint<Or<[fir_ReferenceType.predicate,
-    fir_HeapType.predicate, fir_PointerType.predicate, fir_BoxType.predicate]>,
-    "any reference or box">;
-
-def AnyShapeLike : TypeConstraint<Or<[fir_ShapeType.predicate,
-    fir_ShapeShiftType.predicate]>, "any legal shape type">;
-def AnyShapeType : Type<AnyShapeLike.predicate, "any legal shape type">;
-def fir_SliceType : Type<CPred<"$_self.isa<fir::SliceType>()">, "slice type">;
-
-def AnyEmboxLike : TypeConstraint<Or<[AnySignlessInteger.predicate,
-    Index.predicate, fir_IntegerType.predicate]>,
-    "any legal embox argument type">;
-def AnyEmboxArg : Type<AnyEmboxLike.predicate, "embox argument type">;
-
-// A type descriptor's type
-def fir_TypeDescType : Type<CPred<"$_self.isa<fir::TypeDescType>()">,
-    "type desc type">;
-
-// A LEN parameter (in a RecordType) argument's type
-def fir_LenType : Type<CPred<"$_self.isa<fir::LenType>()">,
-    "LEN parameter type">;
-
-def AnyComponentLike : TypeConstraint<Or<[AnySignlessInteger.predicate,
-    Index.predicate, fir_IntegerType.predicate, fir_FieldType.predicate]>,
-    "any coordinate index">;
-def AnyComponentType : Type<AnyComponentLike.predicate, "coordinate type">;
-
-def AnyCoordinateLike : TypeConstraint<Or<[AnySignlessInteger.predicate,
-    Index.predicate, fir_IntegerType.predicate, fir_FieldType.predicate,
-    fir_LenType.predicate]>, "any coordinate index">;
-def AnyCoordinateType : Type<AnyCoordinateLike.predicate, "coordinate type">;
-
 // Base class for FIR operations.
 // All operations automatically get a prefix of "fir.".
 class fir_Op<string mnemonic, list<OpTrait> traits>
@@ -2251,7 +2163,7 @@ def fir_StringLitOp : fir_Op<"string_lit", [NoSideEffect]> {
     if (!(type.isa<fir::CharacterType>() || type.isa<mlir::IntegerType>()))
       return parser.emitError(parser.getCurrentLocation(),
                               "must have character type");
-    type = fir::SequenceType::get({sz.getInt()}, type);
+    type = fir::SequenceType::get(type.getContext(), {sz.getInt()}, type, {});
     if (!type || parser.addTypesToList(type, result.types))
       return mlir::failure();
     return mlir::success();

diff  --git a/flang/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h
index e8972cfdb5e9..2477b07d1d08 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRType.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRType.h
@@ -41,18 +41,7 @@ class FIROpsDialect;
 using KindTy = unsigned;
 
 namespace detail {
-struct HeapTypeStorage;
-struct IntegerTypeStorage;
-struct LenTypeStorage;
-struct LogicalTypeStorage;
-struct PointerTypeStorage;
-struct RealTypeStorage;
 struct RecordTypeStorage;
-struct ReferenceTypeStorage;
-struct SequenceTypeStorage;
-struct SliceTypeStorage;
-struct TypeDescTypeStorage;
-struct VectorTypeStorage;
 } // namespace detail
 
 // These isa_ routines follow the precedent of llvm::isa_or_null<>
@@ -91,213 +80,6 @@ bool isa_aggregate(mlir::Type t);
 /// not a memory reference type, then returns a null `Type`.
 mlir::Type dyn_cast_ptrEleTy(mlir::Type t);
 
-// Intrinsic types
-
-/// Model of a Fortran INTEGER intrinsic type, including the KIND type
-/// parameter.
-class IntegerType : public mlir::Type::TypeBase<fir::IntegerType, mlir::Type,
-                                                detail::IntegerTypeStorage> {
-public:
-  using Base::Base;
-  static fir::IntegerType get(mlir::MLIRContext *ctxt, KindTy kind);
-  KindTy getFKind() const;
-};
-
-/// Model of a Fortran LOGICAL intrinsic type, including the KIND type
-/// parameter.
-class LogicalType : public mlir::Type::TypeBase<LogicalType, mlir::Type,
-                                                detail::LogicalTypeStorage> {
-public:
-  using Base::Base;
-  static LogicalType get(mlir::MLIRContext *ctxt, KindTy kind);
-  KindTy getFKind() const;
-};
-
-/// Model of a Fortran REAL (and DOUBLE PRECISION) intrinsic type, including the
-/// KIND type parameter.
-class RealType : public mlir::Type::TypeBase<RealType, mlir::Type,
-                                             detail::RealTypeStorage> {
-public:
-  using Base::Base;
-  static RealType get(mlir::MLIRContext *ctxt, KindTy kind);
-  KindTy getFKind() const;
-};
-
-// FIR support types
-
-/// Type of a vector that represents an array slice operation on an array.
-/// Fortran slices are triples of lower bound, upper bound, and stride. The rank
-/// of a SliceType must be at least 1.
-class SliceType : public mlir::Type::TypeBase<SliceType, mlir::Type,
-                                              detail::SliceTypeStorage> {
-public:
-  using Base::Base;
-  static SliceType get(mlir::MLIRContext *ctx, unsigned rank);
-  unsigned getRank() const;
-};
-
-/// The type of a heap pointer. Fortran entities with the ALLOCATABLE attribute
-/// may be allocated on the heap at runtime. These pointers are explicitly
-/// distinguished to disallow the composition of multiple levels of
-/// indirection. For example, an ALLOCATABLE POINTER is invalid.
-class HeapType : public mlir::Type::TypeBase<HeapType, mlir::Type,
-                                             detail::HeapTypeStorage> {
-public:
-  using Base::Base;
-  static HeapType get(mlir::Type elementType);
-
-  mlir::Type getEleTy() const;
-
-  static mlir::LogicalResult
-  verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-         mlir::Type eleTy);
-};
-
-/// The type of a LEN parameter name. Implementations may defer the layout of a
-/// Fortran derived type until runtime. This implies that the runtime must be
-/// able to determine the offset of LEN type parameters related to an entity.
-class LenType
-    : public mlir::Type::TypeBase<LenType, mlir::Type, detail::LenTypeStorage> {
-public:
-  using Base::Base;
-  static LenType get(mlir::MLIRContext *ctxt);
-};
-
-/// The type of entities with the POINTER attribute.  These pointers are
-/// explicitly distinguished to disallow the composition of multiple levels of
-/// indirection. For example, an ALLOCATABLE POINTER is invalid.
-class PointerType : public mlir::Type::TypeBase<PointerType, mlir::Type,
-                                                detail::PointerTypeStorage> {
-public:
-  using Base::Base;
-  static PointerType get(mlir::Type elementType);
-
-  mlir::Type getEleTy() const;
-
-  static mlir::LogicalResult
-  verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-         mlir::Type eleTy);
-};
-
-/// The type of a reference to an entity in memory.
-class ReferenceType
-    : public mlir::Type::TypeBase<ReferenceType, mlir::Type,
-                                  detail::ReferenceTypeStorage> {
-public:
-  using Base::Base;
-  static ReferenceType get(mlir::Type elementType);
-
-  mlir::Type getEleTy() const;
-
-  static mlir::LogicalResult
-  verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-         mlir::Type eleTy);
-};
-
-/// A sequence type is a multi-dimensional array of values. The sequence type
-/// may have an unknown number of dimensions or the extent of dimensions may be
-/// unknown. A sequence type models a Fortran array entity, giving it a type in
-/// FIR. A sequence type is assumed to be stored in a column-major order, which
-/// 
diff ers from LLVM IR and other dialects of MLIR.
-class SequenceType : public mlir::Type::TypeBase<SequenceType, mlir::Type,
-                                                 detail::SequenceTypeStorage> {
-public:
-  using Base::Base;
-  using Extent = int64_t;
-  using Shape = llvm::SmallVector<Extent, 8>;
-
-  /// Return a sequence type with the specified shape and element type
-  static SequenceType get(const Shape &shape, mlir::Type elementType,
-                          mlir::AffineMapAttr map = {});
-
-  /// The element type of this sequence
-  mlir::Type getEleTy() const;
-
-  /// The shape of the sequence. If the sequence has an unknown shape, the shape
-  /// returned will be empty.
-  Shape getShape() const;
-
-  mlir::AffineMapAttr getLayoutMap() const;
-
-  /// The number of dimensions of the sequence
-  unsigned getDimension() const { return getShape().size(); }
-
-  /// Number of rows of constant extent
-  unsigned getConstantRows() const;
-
-  /// Is the shape of the sequence constant?
-  bool hasConstantShape() const { return getConstantRows() == getDimension(); }
-
-  /// Does the sequence have unknown shape? (`array<* x T>`)
-  bool hasUnknownShape() const { return getShape().empty(); }
-
-  /// Is the interior of the sequence constant? Check if the array is
-  /// one of constant shape (`array<C...xCxT>`), unknown shape
-  /// (`array<*xT>`), or rows with shape and ending with column(s) of
-  /// unknown extent (`array<C...xCx?...x?xT>`).
-  bool hasConstantInterior() const;
-
-  /// The value `-1` represents an unknown extent for a dimension
-  static constexpr Extent getUnknownExtent() { return -1; }
-
-  static mlir::LogicalResult
-  verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-         const Shape &shape, mlir::Type eleTy, mlir::AffineMapAttr map);
-};
-
-bool operator==(const SequenceType::Shape &, const SequenceType::Shape &);
-llvm::hash_code hash_value(const SequenceType::Extent &);
-llvm::hash_code hash_value(const SequenceType::Shape &);
-
-/// The type of a type descriptor object. The runtime may generate type
-/// descriptor objects to determine the type of an entity at runtime, etc.
-class TypeDescType : public mlir::Type::TypeBase<TypeDescType, mlir::Type,
-                                                 detail::TypeDescTypeStorage> {
-public:
-  using Base::Base;
-  static TypeDescType get(mlir::Type ofType);
-  mlir::Type getOfTy() const;
-
-  static mlir::LogicalResult
-  verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-         mlir::Type ofType);
-};
-
-// Derived types
-
-/// Model of Fortran's derived type, TYPE. The name of the TYPE includes any
-/// KIND type parameters. The record includes runtime slots for LEN type
-/// parameters and for data components.
-class RecordType : public mlir::Type::TypeBase<RecordType, mlir::Type,
-                                               detail::RecordTypeStorage> {
-public:
-  using Base::Base;
-  using TypePair = std::pair<std::string, mlir::Type>;
-  using TypeList = std::vector<TypePair>;
-
-  llvm::StringRef getName();
-  TypeList getTypeList();
-  TypeList getLenParamList();
-
-  mlir::Type getType(llvm::StringRef ident);
-  mlir::Type getType(unsigned index) {
-    assert(index < getNumFields());
-    return getTypeList()[index].second;
-  }
-  unsigned getNumFields() { return getTypeList().size(); }
-  unsigned getNumLenParams() { return getLenParamList().size(); }
-
-  static RecordType get(mlir::MLIRContext *ctxt, llvm::StringRef name);
-  void finalize(llvm::ArrayRef<TypePair> lenPList,
-                llvm::ArrayRef<TypePair> typeList);
-
-  detail::RecordTypeStorage const *uniqueKey() const;
-
-  static mlir::LogicalResult
-  verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-         llvm::StringRef name);
-};
-
 /// Is `t` a FIR Real or MLIR Float type?
 inline bool isa_real(mlir::Type t) {
   return t.isa<fir::RealType>() || t.isa<mlir::FloatType>();
@@ -309,26 +91,6 @@ inline bool isa_integer(mlir::Type t) {
          t.isa<fir::IntegerType>();
 }
 
-/// Replacement for the builtin vector type.
-/// The FIR vector type is always rank one. It's size is always a constant.
-/// A vector's element type must be real or integer.
-class VectorType : public mlir::Type::TypeBase<fir::VectorType, mlir::Type,
-                                               detail::VectorTypeStorage> {
-public:
-  using Base::Base;
-
-  static fir::VectorType get(uint64_t len, mlir::Type eleTy);
-  mlir::Type getEleTy() const;
-  uint64_t getLen() const;
-
-  static mlir::LogicalResult
-  verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, uint64_t len,
-         mlir::Type eleTy);
-  static bool isValidElementType(mlir::Type t) {
-    return isa_real(t) || isa_integer(t);
-  }
-};
-
 mlir::Type parseFirType(FIROpsDialect *, mlir::DialectAsmParser &parser);
 
 void printFirType(FIROpsDialect *, mlir::Type ty, mlir::DialectAsmPrinter &p);
@@ -353,6 +115,14 @@ inline bool isa_char_string(mlir::Type t) {
 /// of unknown rank or type.
 bool isa_unknown_size_box(mlir::Type t);
 
+#ifndef NDEBUG
+// !fir.ptr<X> and !fir.heap<X> where X is !fir.ptr, !fir.heap, or !fir.ref
+// is undefined and disallowed.
+inline bool singleIndirectionLevel(mlir::Type ty) {
+  return !fir::isa_ref_type(ty);
+}
+#endif
+
 } // namespace fir
 
 #endif // OPTIMIZER_DIALECT_FIRTYPE_H

diff  --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td
index 07c2c58c7c16..a5bbbbdc0798 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td
@@ -23,6 +23,9 @@ class FIR_Type<string name, string typeMnemonic> : TypeDef<fir_Dialect, name> {
   let mnemonic = typeMnemonic;
 }
 
+def fir_Type : Type<CPred<"fir::isa_fir_or_std_type($_self)">,
+    "FIR dialect type">;
+
 def fir_BoxCharType : FIR_Type<"BoxChar", "boxchar"> {
   let summary = "CHARACTER type descriptor.";
 
@@ -34,10 +37,6 @@ def fir_BoxCharType : FIR_Type<"BoxChar", "boxchar"> {
 
   let parameters = (ins "KindTy":$kind);
 
-  let printer = [{
-    $_printer << "boxchar<" << getImpl()->kind << ">";
-  }];
-
   let genAccessors = 1;
 
   let extraClassDeclaration = [{
@@ -61,13 +60,6 @@ def fir_BoxProcType : FIR_Type<"BoxProc", "boxproc"> {
 
   let parameters = (ins "mlir::Type":$eleTy);
 
-  let printer = [{
-    $_printer << "boxproc<";
-    $_printer.printType(getEleTy());
-    $_printer << '>';
-  }];
-
-  let genAccessors = 1;
   let genVerifyDecl = 1;
 }
 
@@ -82,15 +74,21 @@ def fir_BoxType : FIR_Type<"Box", "box"> {
 
   let parameters = (ins "mlir::Type":$eleTy, "mlir::AffineMapAttr":$map);
 
+  let skipDefaultBuilders = 1;
+
+  let builders = [
+    TypeBuilderWithInferredContext<(ins
+        "mlir::Type":$eleTy,
+        CArg<"mlir::AffineMapAttr", "{}">:$map), [{
+      return Base::get(eleTy.getContext(), eleTy, map);
+    }]>,
+  ];
+
   let extraClassDeclaration = [{
     mlir::Type getElementType() const { return getEleTy(); }
     mlir::AffineMapAttr getLayoutMap() const { return getMap(); }
-    static BoxType get(mlir::Type eleTy, mlir::AffineMapAttr map = {}) {
-      return get(eleTy.getContext(), eleTy, map);
-    }
   }];
 
-  let genAccessors = 1;
   let genVerifyDecl = 1;
 }
 
@@ -138,12 +136,6 @@ def fir_ComplexType : FIR_Type<"Complex", "complex"> {
 
   let parameters = (ins "KindTy":$fKind);
 
-  let printer = [{
-    $_printer << "complex<" << getFKind() << '>';
-  }];
-
-  let genAccessors = 1;
-
   let extraClassDeclaration = [{
     using KindTy = unsigned;
 
@@ -159,14 +151,176 @@ def fir_FieldType : FIR_Type<"Field", "field"> {
     derived type until runtime. This implies that the runtime must be able to
     determine the offset of fields within the entity.
   }];
+}
+
+def fir_HeapType : FIR_Type<"Heap", "heap"> {
+  let summary = "Reference to an ALLOCATABLE attribute type";
+
+  let description = [{
+    The type of a heap pointer. Fortran entities with the ALLOCATABLE attribute
+    may be allocated on the heap at runtime. These pointers are explicitly
+    distinguished to disallow the composition of multiple levels of
+    indirection. For example, an ALLOCATABLE POINTER is invalid.
+  }];
+
+  let parameters = (ins "mlir::Type":$eleTy);
+
+  let genVerifyDecl = 1;
+
+  let skipDefaultBuilders = 1;
+
+  let builders = [
+    TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{
+      assert(singleIndirectionLevel(elementType) && "invalid element type");
+      return Base::get(elementType.getContext(), elementType);
+    }]>,
+  ];
+}
+
+def fir_IntegerType : FIR_Type<"Integer", "int"> {
+  let summary = "FIR integer type";
+
+  let description = [{
+    Model of a Fortran INTEGER intrinsic type, including the KIND type
+    parameter.
+  }];
+
+  let parameters = (ins "KindTy":$fKind);
+
+  let extraClassDeclaration = [{
+    using KindTy = unsigned;
+  }];
+}
+
+def fir_LenType : FIR_Type<"Len", "len"> {
+  let summary = "A LEN parameter (in a RecordType) argument's type";
+
+  let description = [{
+    The type of a LEN parameter name. Implementations may defer the layout of a
+    Fortran derived type until runtime. This implies that the runtime must be
+    able to determine the offset of LEN type parameters related to an entity.
+  }];
+}
+
+def fir_LogicalType : FIR_Type<"Logical", "logical"> {
+  let summary = "FIR logical type";
+
+  let description = [{
+    Model of a Fortran LOGICAL intrinsic type, including the KIND type
+    parameter.
+  }];
+
+  let parameters = (ins "KindTy":$fKind);
+
+  let extraClassDeclaration = [{
+    using KindTy = unsigned;
+  }];
+}
+
+def fir_PointerType : FIR_Type<"Pointer", "ptr"> {
+  let summary = "Reference to a POINTER attribute type";
+
+  let description = [{
+    The type of entities with the POINTER attribute.  These pointers are
+    explicitly distinguished to disallow the composition of multiple levels of
+    indirection. For example, an ALLOCATABLE POINTER is invalid.
+  }];
+
+  let parameters = (ins "mlir::Type":$eleTy);
+
+  let genVerifyDecl = 1;
+
+  let skipDefaultBuilders = 1;
+
+  let builders = [
+    TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{
+      assert(singleIndirectionLevel(elementType) && "invalid element type");
+      return Base::get(elementType.getContext(), elementType);
+    }]>,
+  ];
+
+  let extraClassDeclaration = [{
+    mlir::Type getElementType() const { return getEleTy(); }
+  }];
+}
+
+def fir_RealType : FIR_Type<"Real", "real"> {
+  let summary = "FIR real type";
+
+  let description = [{
+    Model of a Fortran REAL (and DOUBLE PRECISION) intrinsic type, including the
+    KIND type parameter.
+  }];
+
+  let parameters = (ins "KindTy":$fKind);
+
+  let extraClassDeclaration = [{
+    using KindTy = unsigned;
+  }];
+
+  let genVerifyDecl = 1;
+}
+
+def fir_RecordType : FIR_Type<"Record", "type"> {
+  let summary = "FIR derived type";
+
+  let description = [{
+    Model of Fortran's derived type, TYPE. The name of the TYPE includes any
+    KIND type parameters. The record includes runtime slots for LEN type
+    parameters and for data components.
+  }];
+
+  let parameters = (ins StringRefParameter<"name">:$name);
+
+  let genVerifyDecl = 1;
+  let genStorageClass = 0;
 
-  let printer = [{
-    $_printer << "field";
+  let extraClassDeclaration = [{
+    using TypePair = std::pair<std::string, mlir::Type>;
+    using TypeList = std::vector<TypePair>;
+    TypeList getTypeList() const;
+    TypeList getLenParamList() const;
+
+    mlir::Type getType(llvm::StringRef ident);
+    // Returns the index of the field \p ident in the type list.
+    // Returns maximum unsigned if ident is not a field of this RecordType.
+    unsigned getFieldIndex(llvm::StringRef ident);
+    mlir::Type getType(unsigned index) {
+      assert(index < getNumFields());
+      return getTypeList()[index].second;
+    }
+    unsigned getNumFields() { return getTypeList().size(); }
+    unsigned getNumLenParams() { return getLenParamList().size(); }
+
+    void finalize(llvm::ArrayRef<TypePair> lenPList,
+                  llvm::ArrayRef<TypePair> typeList);
+
+    detail::RecordTypeStorage const *uniqueKey() const;
   }];
+}
 
-  let parser = [{
-    return get(context);
+def fir_ReferenceType : FIR_Type<"Reference", "ref"> {
+  let summary = "Reference to an entity type";
+
+  let description = [{
+    The type of a reference to an entity in memory.
   }];
+
+  let parameters = (ins "mlir::Type":$eleTy);
+
+  let skipDefaultBuilders = 1;
+
+  let builders = [
+    TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{
+      return Base::get(elementType.getContext(), elementType);
+    }]>,
+  ];
+
+  let extraClassDeclaration = [{
+    mlir::Type getElementType() const { return getEleTy(); }
+  }];
+
+  let genVerifyDecl = 1;
 }
 
 def fir_ShapeType : FIR_Type<"Shape", "shape"> {
@@ -179,18 +333,6 @@ def fir_ShapeType : FIR_Type<"Shape", "shape"> {
   }];
 
   let parameters = (ins "unsigned":$rank);
-
-  let printer = [{
-    $_printer << "shape<" << getImpl()->rank << ">";
-  }];
-
-  let parser = [{
-    int rank;
-    if ($_parser.parseLess() || $_parser.parseInteger(rank) ||
-        $_parser.parseGreater())
-      return Type();
-    return get(context, rank);
-  }];
 }
 
 def fir_ShapeShiftType : FIR_Type<"ShapeShift", "shapeshift"> {
@@ -204,18 +346,6 @@ def fir_ShapeShiftType : FIR_Type<"ShapeShift", "shapeshift"> {
   }];
 
   let parameters = (ins "unsigned":$rank);
-
-  let printer = [{
-    $_printer << "shapeshift<" << getImpl()->rank << ">";
-  }];
-
-  let parser = [{
-    int rank;
-    if ($_parser.parseLess() || $_parser.parseInteger(rank) ||
-        $_parser.parseGreater())
-      return Type();
-    return get(context, rank);
-  }];
 }
 
 def fir_ShiftType : FIR_Type<"Shift", "shift"> {
@@ -229,17 +359,189 @@ def fir_ShiftType : FIR_Type<"Shift", "shift"> {
 
   let parameters = (ins "unsigned":$rank);
 
-  let printer = [{
-    $_printer << "shift<" << getImpl()->rank << ">";
+  let extraClassDeclaration = [{
+    using KindTy = unsigned;
+
+    // a !fir.boxchar<k> always wraps a !fir.char<k, ?>
+    CharacterType getElementType(mlir::MLIRContext *context) const;
+
+    CharacterType getEleTy() const;
+  }];
+}
+
+def fir_SequenceType : FIR_Type<"Sequence", "array"> {
+  let summary = "FIR array type";
+
+  let description = [{
+    A sequence type is a multi-dimensional array of values. The sequence type
+    may have an unknown number of dimensions or the extent of dimensions may be
+    unknown. A sequence type models a Fortran array entity, giving it a type in
+    FIR. A sequence type is assumed to be stored in a column-major order, which
+    
diff ers from LLVM IR and other dialects of MLIR.
+  }];
+
+  let parameters = (ins
+    ArrayRefParameter<"int64_t", "Sequence shape">:$shape,
+    "mlir::Type":$eleTy,
+    "mlir::AffineMapAttr":$layoutMap
+  );
+
+  let genVerifyDecl = 1;
+
+  let builders = [
+    TypeBuilderWithInferredContext<(ins
+        "llvm::ArrayRef<int64_t>":$shape,
+        "mlir::Type":$eleTy), [{
+      return get(eleTy.getContext(), shape, eleTy, {});
+    }]>,
+  ];
+
+  let extraClassDeclaration = [{
+    using Extent = int64_t;
+    using Shape = llvm::SmallVector<Extent, 8>;
+    using ShapeRef = llvm::ArrayRef<int64_t>;
+    unsigned getConstantRows() const;
+
+    // The number of dimensions of the sequence
+    unsigned getDimension() const { return getShape().size(); }
+
+    // Is the interior of the sequence constant? Check if the array is
+    // one of constant shape (`array<C...xCxT>`), unknown shape
+    // (`array<*xT>`), or rows with shape and ending with column(s) of
+    // unknown extent (`array<C...xCx?...x?xT>`).
+    bool hasConstantInterior() const;
+
+    // Is the shape of the sequence constant?
+    bool hasConstantShape() const { return getConstantRows() == getDimension(); }
+
+    // Does the sequence have unknown shape? (`array<* x T>`)
+    bool hasUnknownShape() const { return getShape().empty(); }
+
+    // The value `-1` represents an unknown extent for a dimension
+    static constexpr Extent getUnknownExtent() { return -1; }
+  }];
+}
+
+def fir_SliceType : FIR_Type<"Slice", "slice"> {
+  let summary = "FIR slice";
+
+  let description = [{
+    Type of a vector that represents an array slice operation on an array.
+    Fortran slices are triples of lower bound, upper bound, and stride. The rank
+    of a SliceType must be at least 1.
+  }];
+
+  let parameters = (ins "unsigned":$rank);
+}
+
+def fir_TypeDescType : FIR_Type<"TypeDesc", "tdesc"> {
+  let summary = "FIR Type descriptor type";
+
+  let description = [{
+    The type of a type descriptor object. The runtime may generate type
+    descriptor objects to determine the type of an entity at runtime, etc.
   }];
 
-  let parser = [{
-    int rank;
-    if ($_parser.parseLess() || $_parser.parseInteger(rank) ||
-        $_parser.parseGreater())
-      return Type();
-    return get(context, rank);
+  let parameters = (ins "mlir::Type":$ofTy);
+
+  let genVerifyDecl = 1;
+
+  let skipDefaultBuilders = 1;
+
+  let builders = [
+    TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{
+      return Base::get(elementType.getContext(), elementType);
+    }]>,
+  ];
+}
+
+def fir_VectorType : FIR_Type<"Vector", "vector"> {
+  let summary = "FIR vector type";
+
+  let description = [{
+    Replacement for the builtin vector type.
+    The FIR vector type is always rank one. It's size is always a constant.
+    A vector's element type must be real or integer.
   }];
+
+  let parameters = (ins "uint64_t":$len, "mlir::Type":$eleTy);
+
+  let genVerifyDecl = 1;
+
+  let extraClassDeclaration = [{
+    static bool isValidElementType(mlir::Type t);
+  }];
+
+  let skipDefaultBuilders = 1;
+
+  let builders = [
+    TypeBuilderWithInferredContext<(ins
+        "uint64_t":$len,
+        "mlir::Type":$eleTy), [{
+      return Base::get(eleTy.getContext(), len, eleTy);
+    }]>,
+  ];
 }
 
+def fir_VoidType : FIR_Type<"Void", "void"> {
+  let genStorageClass = 0;
+}
+
+// Generalized FIR and standard dialect types representing intrinsic types
+def AnyIntegerLike : TypeConstraint<Or<[SignlessIntegerLike.predicate,
+    AnySignedInteger.predicate, fir_IntegerType.predicate]>, "any integer">;
+def AnyLogicalLike : TypeConstraint<Or<[BoolLike.predicate,
+    fir_LogicalType.predicate]>, "any logical">;
+def AnyRealLike : TypeConstraint<Or<[FloatLike.predicate,
+    fir_RealType.predicate]>, "any real">;
+def AnyIntegerType : Type<AnyIntegerLike.predicate, "any integer">;
+
+// Composable types
+def AnyCompositeLike : TypeConstraint<Or<[fir_RecordType.predicate,
+    fir_SequenceType.predicate, fir_ComplexType.predicate,
+    fir_VectorType.predicate, IsTupleTypePred, fir_CharacterType.predicate]>,
+    "any composite">;
+
+// Reference types
+def AnyReferenceLike : TypeConstraint<Or<[fir_ReferenceType.predicate,
+    fir_HeapType.predicate, fir_PointerType.predicate]>, "any reference">;
+
+def AnyBoxLike : TypeConstraint<Or<[fir_BoxType.predicate,
+    fir_BoxCharType.predicate, fir_BoxProcType.predicate]>, "any box">;
+
+def AnyRefOrBoxLike : TypeConstraint<Or<[AnyReferenceLike.predicate,
+    AnyBoxLike.predicate]>,
+    "any reference or box like">;
+def AnyRefOrBox : TypeConstraint<Or<[fir_ReferenceType.predicate,
+    fir_HeapType.predicate, fir_PointerType.predicate, fir_BoxType.predicate]>,
+    "any reference or box">;
+
+def AnyShapeLike : TypeConstraint<Or<[fir_ShapeType.predicate,
+    fir_ShapeShiftType.predicate]>, "any legal shape type">;
+def AnyShapeType : Type<AnyShapeLike.predicate, "any legal shape type">;
+def AnyShapeOrShiftLike : TypeConstraint<Or<[fir_ShapeType.predicate,
+    fir_ShapeShiftType.predicate, fir_ShiftType.predicate]>,
+    "any legal shape or shift type">;
+def AnyShapeOrShiftType : Type<AnyShapeOrShiftLike.predicate,
+    "any legal shape or shift type">;
+
+def AnyEmboxLike : TypeConstraint<Or<[AnySignlessInteger.predicate,
+    Index.predicate, fir_IntegerType.predicate]>,
+    "any legal embox argument type">;
+def AnyEmboxArg : Type<AnyEmboxLike.predicate, "embox argument type">;
+
+def AnyComponentLike : TypeConstraint<Or<[AnySignlessInteger.predicate,
+    Index.predicate, fir_IntegerType.predicate, fir_FieldType.predicate]>,
+    "any coordinate index">;
+def AnyComponentType : Type<AnyComponentLike.predicate, "coordinate type">;
+
+def AnyCoordinateLike : TypeConstraint<Or<[AnySignlessInteger.predicate,
+    Index.predicate, fir_IntegerType.predicate, fir_FieldType.predicate,
+    fir_LenType.predicate]>, "any coordinate index">;
+def AnyCoordinateType : Type<AnyCoordinateLike.predicate, "coordinate type">;
+
+// The legal types of global symbols
+def AnyAddressableLike : TypeConstraint<Or<[fir_ReferenceType.predicate,
+    FunctionType.predicate]>, "any addressable">;
+
 #endif // FIR_DIALECT_FIR_TYPES

diff  --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index ecfc597d820a..4cbdf15f38d6 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -49,7 +49,7 @@ TYPE parseRankSingleton(mlir::DialectAsmParser &parser) {
 }
 
 template <typename TYPE>
-TYPE parseTypeSingleton(mlir::DialectAsmParser &parser, mlir::Location) {
+TYPE parseTypeSingleton(mlir::DialectAsmParser &parser) {
   mlir::Type ty;
   if (parser.parseLess() || parser.parseType(ty) || parser.parseGreater()) {
     parser.emitError(parser.getCurrentLocation(), "type expected");
@@ -58,101 +58,6 @@ TYPE parseTypeSingleton(mlir::DialectAsmParser &parser, mlir::Location) {
   return TYPE::get(ty);
 }
 
-// `slice` `<` rank `>`
-SliceType parseSlice(mlir::DialectAsmParser &parser) {
-  return parseRankSingleton<SliceType>(parser);
-}
-
-// `heap` `<` type `>`
-HeapType parseHeap(mlir::DialectAsmParser &parser, mlir::Location loc) {
-  return parseTypeSingleton<HeapType>(parser, loc);
-}
-
-// `int` `<` kind `>`
-fir::IntegerType parseInteger(mlir::DialectAsmParser &parser) {
-  return parseKindSingleton<fir::IntegerType>(parser);
-}
-
-// `len`
-LenType parseLen(mlir::DialectAsmParser &parser) {
-  return LenType::get(parser.getBuilder().getContext());
-}
-
-// `logical` `<` kind `>`
-LogicalType parseLogical(mlir::DialectAsmParser &parser) {
-  return parseKindSingleton<LogicalType>(parser);
-}
-
-// `ptr` `<` type `>`
-PointerType parsePointer(mlir::DialectAsmParser &parser, mlir::Location loc) {
-  return parseTypeSingleton<PointerType>(parser, loc);
-}
-
-// `real` `<` kind `>`
-RealType parseReal(mlir::DialectAsmParser &parser) {
-  return parseKindSingleton<RealType>(parser);
-}
-
-// `ref` `<` type `>`
-ReferenceType parseReference(mlir::DialectAsmParser &parser,
-                             mlir::Location loc) {
-  return parseTypeSingleton<ReferenceType>(parser, loc);
-}
-
-// `tdesc` `<` type `>`
-TypeDescType parseTypeDesc(mlir::DialectAsmParser &parser, mlir::Location loc) {
-  return parseTypeSingleton<TypeDescType>(parser, loc);
-}
-
-// `vector` `<` len `:` type `>`
-fir::VectorType parseVector(mlir::DialectAsmParser &parser,
-                            mlir::Location loc) {
-  int64_t len = 0;
-  mlir::Type eleTy;
-  if (parser.parseLess() || parser.parseInteger(len) || parser.parseColon() ||
-      parser.parseType(eleTy) || parser.parseGreater()) {
-    parser.emitError(parser.getNameLoc(), "invalid vector type");
-    return {};
-  }
-  return fir::VectorType::get(len, eleTy);
-}
-
-// `void`
-mlir::Type parseVoid(mlir::DialectAsmParser &parser) {
-  return parser.getBuilder().getNoneType();
-}
-
-// `array` `<` `*` | bounds (`x` bounds)* `:` type (',' affine-map)? `>`
-// bounds ::= `?` | int-lit
-SequenceType parseSequence(mlir::DialectAsmParser &parser, mlir::Location) {
-  if (parser.parseLess()) {
-    parser.emitError(parser.getNameLoc(), "expecting '<'");
-    return {};
-  }
-  SequenceType::Shape shape;
-  if (parser.parseOptionalStar()) {
-    if (parser.parseDimensionList(shape, /*allowDynamic=*/true)) {
-      parser.emitError(parser.getNameLoc(), "invalid shape");
-      return {};
-    }
-  } else if (parser.parseColon()) {
-    parser.emitError(parser.getNameLoc(), "expected ':'");
-    return {};
-  }
-  mlir::Type eleTy;
-  if (parser.parseType(eleTy) || parser.parseGreater()) {
-    parser.emitError(parser.getNameLoc(), "expecting element type");
-    return {};
-  }
-  mlir::AffineMapAttr map;
-  if (!parser.parseOptionalComma())
-    if (parser.parseAttribute(map)) {
-      parser.emitError(parser.getNameLoc(), "expecting affine map");
-      return {};
-    }
-  return SequenceType::get(shape, eleTy, map);
-}
-
 /// Is `ty` a standard or FIR integer type?
 static bool isaIntegerType(mlir::Type ty) {
   // TODO: why aren't we using isa_integer? investigatation required.
@@ -206,79 +111,6 @@ RecordType verifyDerived(mlir::DialectAsmParser &parser, RecordType derivedTy,
   return derivedTy;
 }
 
-// Fortran derived type
-// `type` `<` name
-//           (`(` id `:` type (`,` id `:` type)* `)`)?
-//           (`{` id `:` type (`,` id `:` type)* `}`)? '>'
-RecordType parseDerived(mlir::DialectAsmParser &parser, mlir::Location) {
-  llvm::StringRef name;
-  if (parser.parseLess() || parser.parseKeyword(&name)) {
-    parser.emitError(parser.getNameLoc(),
-                     "expected a identifier as name of derived type");
-    return {};
-  }
-  RecordType result = RecordType::get(parser.getBuilder().getContext(), name);
-
-  RecordType::TypeList lenParamList;
-  if (!parser.parseOptionalLParen()) {
-    while (true) {
-      llvm::StringRef lenparam;
-      mlir::Type intTy;
-      if (parser.parseKeyword(&lenparam) || parser.parseColon() ||
-          parser.parseType(intTy)) {
-        parser.emitError(parser.getNameLoc(), "expected LEN parameter list");
-        return {};
-      }
-      lenParamList.emplace_back(lenparam, intTy);
-      if (parser.parseOptionalComma())
-        break;
-    }
-    if (parser.parseRParen()) {
-      parser.emitError(parser.getNameLoc(), "expected ')'");
-      return {};
-    }
-  }
-
-  RecordType::TypeList typeList;
-  if (!parser.parseOptionalLBrace()) {
-    while (true) {
-      llvm::StringRef field;
-      mlir::Type fldTy;
-      if (parser.parseKeyword(&field) || parser.parseColon() ||
-          parser.parseType(fldTy)) {
-        parser.emitError(parser.getNameLoc(), "expected field type list");
-        return {};
-      }
-      typeList.emplace_back(field, fldTy);
-      if (parser.parseOptionalComma())
-        break;
-    }
-    if (parser.parseRBrace()) {
-      parser.emitError(parser.getNameLoc(), "expected '}'");
-      return {};
-    }
-  }
-
-  if (parser.parseGreater()) {
-    parser.emitError(parser.getNameLoc(), "expected '>' in type type");
-    return {};
-  }
-
-  if (lenParamList.empty() && typeList.empty())
-    return result;
-
-  result.finalize(lenParamList, typeList);
-  return verifyDerived(parser, result, lenParamList, typeList);
-}
-
-#ifndef NDEBUG
-// !fir.ptr<X> and !fir.heap<X> where X is !fir.ptr, !fir.heap, or !fir.ref
-// is undefined and disallowed.
-inline bool singleIndirectionLevel(mlir::Type ty) {
-  return !fir::isa_ref_type(ty);
-}
-#endif
-
 } // namespace
 
 // Implementation of the thin interface from dialect to type parser
@@ -287,57 +119,9 @@ mlir::Type fir::parseFirType(FIROpsDialect *dialect,
                              mlir::DialectAsmParser &parser) {
   llvm::StringRef typeNameLit;
   if (mlir::failed(parser.parseKeyword(&typeNameLit)))
-    return {};
+    return mlir::Type();
 
-  // TODO all TYPE::parse can be move to generatedTypeParser when all types
-  // have been moved
-
-  auto loc = parser.getEncodedSourceLoc(parser.getNameLoc());
-  if (typeNameLit == "array")
-    return parseSequence(parser, loc);
-  if (typeNameLit == "box")
-    return generatedTypeParser(dialect->getContext(), parser, typeNameLit);
-  if (typeNameLit == "boxchar")
-    return generatedTypeParser(dialect->getContext(), parser, typeNameLit);
-  if (typeNameLit == "boxproc")
-    return generatedTypeParser(dialect->getContext(), parser, typeNameLit);
-  if (typeNameLit == "char")
-    return generatedTypeParser(dialect->getContext(), parser, typeNameLit);
-  if (typeNameLit == "complex")
-    return generatedTypeParser(dialect->getContext(), parser, typeNameLit);
-  if (typeNameLit == "field")
-    return generatedTypeParser(dialect->getContext(), parser, typeNameLit);
-  if (typeNameLit == "heap")
-    return parseHeap(parser, loc);
-  if (typeNameLit == "int")
-    return parseInteger(parser);
-  if (typeNameLit == "len")
-    return parseLen(parser);
-  if (typeNameLit == "logical")
-    return parseLogical(parser);
-  if (typeNameLit == "ptr")
-    return parsePointer(parser, loc);
-  if (typeNameLit == "real")
-    return parseReal(parser);
-  if (typeNameLit == "ref")
-    return parseReference(parser, loc);
-  if (typeNameLit == "shape")
-    return generatedTypeParser(dialect->getContext(), parser, typeNameLit);
-  if (typeNameLit == "shapeshift")
-    return generatedTypeParser(dialect->getContext(), parser, typeNameLit);
-  if (typeNameLit == "slice")
-    return parseSlice(parser);
-  if (typeNameLit == "tdesc")
-    return parseTypeDesc(parser, loc);
-  if (typeNameLit == "type")
-    return parseDerived(parser, loc);
-  if (typeNameLit == "void")
-    return parseVoid(parser);
-  if (typeNameLit == "vector")
-    return parseVector(parser, loc);
-
-  parser.emitError(parser.getNameLoc(), "unknown FIR type " + typeNameLit);
-  return {};
+  return generatedTypeParser(dialect->getContext(), parser, typeNameLit);
 }
 
 namespace fir {
@@ -345,234 +129,6 @@ namespace detail {
 
 // Type storage classes
 
-struct SliceTypeStorage : public mlir::TypeStorage {
-  using KeyTy = unsigned;
-
-  static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
-
-  bool operator==(const KeyTy &key) const { return key == getRank(); }
-
-  static SliceTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                     unsigned rank) {
-    auto *storage = allocator.allocate<SliceTypeStorage>();
-    return new (storage) SliceTypeStorage{rank};
-  }
-
-  unsigned getRank() const { return rank; }
-
-protected:
-  unsigned rank;
-
-private:
-  SliceTypeStorage() = delete;
-  explicit SliceTypeStorage(unsigned rank) : rank{rank} {}
-};
-
-/// The type of a derived type LEN parameter reference
-struct LenTypeStorage : public mlir::TypeStorage {
-  using KeyTy = KindTy;
-
-  static unsigned hashKey(const KeyTy &) { return llvm::hash_combine(0); }
-
-  bool operator==(const KeyTy &) const { return true; }
-
-  static LenTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                   KindTy) {
-    auto *storage = allocator.allocate<LenTypeStorage>();
-    return new (storage) LenTypeStorage{0};
-  }
-
-private:
-  LenTypeStorage() = delete;
-  explicit LenTypeStorage(KindTy) {}
-};
-
-/// `LOGICAL` storage
-struct LogicalTypeStorage : public mlir::TypeStorage {
-  using KeyTy = KindTy;
-
-  static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
-
-  bool operator==(const KeyTy &key) const { return key == getFKind(); }
-
-  static LogicalTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                       KindTy kind) {
-    auto *storage = allocator.allocate<LogicalTypeStorage>();
-    return new (storage) LogicalTypeStorage{kind};
-  }
-
-  KindTy getFKind() const { return kind; }
-
-protected:
-  KindTy kind;
-
-private:
-  LogicalTypeStorage() = delete;
-  explicit LogicalTypeStorage(KindTy kind) : kind{kind} {}
-};
-
-/// `INTEGER` storage
-struct IntegerTypeStorage : public mlir::TypeStorage {
-  using KeyTy = KindTy;
-
-  static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
-
-  bool operator==(const KeyTy &key) const { return key == getFKind(); }
-
-  static IntegerTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                       KindTy kind) {
-    auto *storage = allocator.allocate<IntegerTypeStorage>();
-    return new (storage) IntegerTypeStorage{kind};
-  }
-
-  KindTy getFKind() const { return kind; }
-
-protected:
-  KindTy kind;
-
-private:
-  IntegerTypeStorage() = delete;
-  explicit IntegerTypeStorage(KindTy kind) : kind{kind} {}
-};
-
-/// `REAL` storage (for reals of unsupported sizes)
-struct RealTypeStorage : public mlir::TypeStorage {
-  using KeyTy = KindTy;
-
-  static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
-
-  bool operator==(const KeyTy &key) const { return key == getFKind(); }
-
-  static RealTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                    KindTy kind) {
-    auto *storage = allocator.allocate<RealTypeStorage>();
-    return new (storage) RealTypeStorage{kind};
-  }
-
-  KindTy getFKind() const { return kind; }
-
-protected:
-  KindTy kind;
-
-private:
-  RealTypeStorage() = delete;
-  explicit RealTypeStorage(KindTy kind) : kind{kind} {}
-};
-
-/// Pointer-like object storage
-struct ReferenceTypeStorage : public mlir::TypeStorage {
-  using KeyTy = mlir::Type;
-
-  static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
-
-  bool operator==(const KeyTy &key) const { return key == getElementType(); }
-
-  static ReferenceTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                         mlir::Type eleTy) {
-    assert(eleTy && "element type is null");
-    auto *storage = allocator.allocate<ReferenceTypeStorage>();
-    return new (storage) ReferenceTypeStorage{eleTy};
-  }
-
-  mlir::Type getElementType() const { return eleTy; }
-
-protected:
-  mlir::Type eleTy;
-
-private:
-  ReferenceTypeStorage() = delete;
-  explicit ReferenceTypeStorage(mlir::Type eleTy) : eleTy{eleTy} {}
-};
-
-/// Pointer object storage
-struct PointerTypeStorage : public mlir::TypeStorage {
-  using KeyTy = mlir::Type;
-
-  static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
-
-  bool operator==(const KeyTy &key) const { return key == getElementType(); }
-
-  static PointerTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                       mlir::Type eleTy) {
-    assert(eleTy && "element type is null");
-    auto *storage = allocator.allocate<PointerTypeStorage>();
-    return new (storage) PointerTypeStorage{eleTy};
-  }
-
-  mlir::Type getElementType() const { return eleTy; }
-
-protected:
-  mlir::Type eleTy;
-
-private:
-  PointerTypeStorage() = delete;
-  explicit PointerTypeStorage(mlir::Type eleTy) : eleTy{eleTy} {}
-};
-
-/// Heap memory reference object storage
-struct HeapTypeStorage : public mlir::TypeStorage {
-  using KeyTy = mlir::Type;
-
-  static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
-
-  bool operator==(const KeyTy &key) const { return key == getElementType(); }
-
-  static HeapTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                    mlir::Type eleTy) {
-    assert(eleTy && "element type is null");
-    auto *storage = allocator.allocate<HeapTypeStorage>();
-    return new (storage) HeapTypeStorage{eleTy};
-  }
-
-  mlir::Type getElementType() const { return eleTy; }
-
-protected:
-  mlir::Type eleTy;
-
-private:
-  HeapTypeStorage() = delete;
-  explicit HeapTypeStorage(mlir::Type eleTy) : eleTy{eleTy} {}
-};
-
-/// Sequence-like object storage
-struct SequenceTypeStorage : public mlir::TypeStorage {
-  using KeyTy =
-      std::tuple<SequenceType::Shape, mlir::Type, mlir::AffineMapAttr>;
-
-  static unsigned hashKey(const KeyTy &key) {
-    auto shapeHash = hash_value(std::get<SequenceType::Shape>(key));
-    shapeHash = llvm::hash_combine(shapeHash, std::get<mlir::Type>(key));
-    return llvm::hash_combine(shapeHash, std::get<mlir::AffineMapAttr>(key));
-  }
-
-  bool operator==(const KeyTy &key) const {
-    return key == KeyTy{getShape(), getElementType(), getLayoutMap()};
-  }
-
-  static SequenceTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                        const KeyTy &key) {
-    auto *storage = allocator.allocate<SequenceTypeStorage>();
-    return new (storage) SequenceTypeStorage{
-        std::get<SequenceType::Shape>(key), std::get<mlir::Type>(key),
-        std::get<mlir::AffineMapAttr>(key)};
-  }
-
-  SequenceType::Shape getShape() const { return shape; }
-  mlir::Type getElementType() const { return eleTy; }
-  mlir::AffineMapAttr getLayoutMap() const { return map; }
-
-protected:
-  SequenceType::Shape shape;
-  mlir::Type eleTy;
-  mlir::AffineMapAttr map;
-
-private:
-  SequenceTypeStorage() = delete;
-  explicit SequenceTypeStorage(const SequenceType::Shape &shape,
-                               mlir::Type eleTy, mlir::AffineMapAttr map)
-      : shape{shape}, eleTy{eleTy}, map{map} {}
-};
-
 /// Derived type storage
 struct RecordTypeStorage : public mlir::TypeStorage {
   using KeyTy = llvm::StringRef;
@@ -620,78 +176,20 @@ struct RecordTypeStorage : public mlir::TypeStorage {
       : name{name}, finalized{false} {}
 };
 
-/// Type descriptor type storage
-struct TypeDescTypeStorage : public mlir::TypeStorage {
-  using KeyTy = mlir::Type;
-
-  static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
-
-  bool operator==(const KeyTy &key) const { return key == getOfType(); }
+} // namespace detail
 
-  static TypeDescTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                        mlir::Type ofTy) {
-    assert(ofTy && "descriptor type is null");
-    auto *storage = allocator.allocate<TypeDescTypeStorage>();
-    return new (storage) TypeDescTypeStorage{ofTy};
-  }
+template <typename A, typename B>
+bool inbounds(A v, B lb, B ub) {
+  return v >= lb && v < ub;
+}
 
-  // The type described by this type descriptor instance
-  mlir::Type getOfType() const { return ofTy; }
+bool isa_fir_type(mlir::Type t) {
+  return llvm::isa<FIROpsDialect>(t.getDialect());
+}
 
-protected:
-  mlir::Type ofTy;
-
-private:
-  TypeDescTypeStorage() = delete;
-  explicit TypeDescTypeStorage(mlir::Type ofTy) : ofTy{ofTy} {}
-};
-
-/// Vector type storage
-struct VectorTypeStorage : public mlir::TypeStorage {
-  using KeyTy = std::tuple<uint64_t, mlir::Type>;
-
-  static unsigned hashKey(const KeyTy &key) {
-    return llvm::hash_combine(std::get<uint64_t>(key),
-                              std::get<mlir::Type>(key));
-  }
-
-  bool operator==(const KeyTy &key) const {
-    return key == KeyTy{getLen(), getEleTy()};
-  }
-
-  static VectorTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
-                                      const KeyTy &key) {
-    auto *storage = allocator.allocate<VectorTypeStorage>();
-    return new (storage)
-        VectorTypeStorage{std::get<uint64_t>(key), std::get<mlir::Type>(key)};
-  }
-
-  uint64_t getLen() const { return len; }
-  mlir::Type getEleTy() const { return eleTy; }
-
-protected:
-  uint64_t len;
-  mlir::Type eleTy;
-
-private:
-  VectorTypeStorage() = delete;
-  explicit VectorTypeStorage(uint64_t len, mlir::Type eleTy)
-      : len{len}, eleTy{eleTy} {}
-};
-
-} // namespace detail
-
-template <typename A, typename B> bool inbounds(A v, B lb, B ub) {
-  return v >= lb && v < ub;
-}
-
-bool isa_fir_type(mlir::Type t) {
-  return llvm::isa<FIROpsDialect>(t.getDialect());
-}
-
-bool isa_std_type(mlir::Type t) {
-  return t.getDialect().getNamespace().empty();
-}
+bool isa_std_type(mlir::Type t) {
+  return t.getDialect().getNamespace().empty();
+}
 
 bool isa_fir_or_std_type(mlir::Type t) {
   if (auto funcType = t.dyn_cast<mlir::FunctionType>())
@@ -727,101 +225,212 @@ mlir::Type dyn_cast_ptrEleTy(mlir::Type t) {
 
 } // namespace fir
 
-// Len
+namespace {
+
+static llvm::SmallPtrSet<detail::RecordTypeStorage const *, 4>
+    recordTypeVisited;
+
+} // namespace
+
+void fir::verifyIntegralType(mlir::Type type) {
+  if (isaIntegerType(type) || type.isa<mlir::IndexType>())
+    return;
+  llvm::report_fatal_error("expected integral type");
+}
+
+void fir::printFirType(FIROpsDialect *, mlir::Type ty,
+                       mlir::DialectAsmPrinter &p) {
+  if (mlir::failed(generatedTypePrinter(ty, p)))
+    llvm::report_fatal_error("unknown type to print");
+}
 
-LenType fir::LenType::get(mlir::MLIRContext *ctxt) {
-  return Base::get(ctxt, 0);
+bool fir::isa_unknown_size_box(mlir::Type t) {
+  if (auto boxTy = t.dyn_cast<fir::BoxType>()) {
+    auto eleTy = boxTy.getEleTy();
+    if (auto actualEleTy = fir::dyn_cast_ptrEleTy(eleTy))
+      eleTy = actualEleTy;
+    if (eleTy.isa<mlir::NoneType>())
+      return true;
+    if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>())
+      if (seqTy.hasUnknownShape())
+        return true;
+  }
+  return false;
 }
 
-// LOGICAL
+//===----------------------------------------------------------------------===//
+// BoxProcType
+//===----------------------------------------------------------------------===//
 
-LogicalType fir::LogicalType::get(mlir::MLIRContext *ctxt, KindTy kind) {
-  return Base::get(ctxt, kind);
+// `boxproc` `<` return-type `>`
+mlir::Type BoxProcType::parse(mlir::MLIRContext *context,
+                              mlir::DialectAsmParser &parser) {
+  mlir::Type ty;
+  if (parser.parseLess() || parser.parseType(ty) || parser.parseGreater()) {
+    parser.emitError(parser.getCurrentLocation(), "type expected");
+    return {};
+  }
+  return get(context, ty);
 }
 
-KindTy fir::LogicalType::getFKind() const { return getImpl()->getFKind(); }
+void fir::BoxProcType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getEleTy() << '>';
+}
 
-// INTEGER
+mlir::LogicalResult
+BoxProcType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
+                    mlir::Type eleTy) {
+  if (eleTy.isa<mlir::FunctionType>())
+    return mlir::success();
+  if (auto refTy = eleTy.dyn_cast<ReferenceType>())
+    if (refTy.isa<mlir::FunctionType>())
+      return mlir::success();
+  return emitError() << "invalid type for boxproc" << eleTy << '\n';
+}
 
-fir::IntegerType fir::IntegerType::get(mlir::MLIRContext *ctxt, KindTy kind) {
-  return Base::get(ctxt, kind);
+static bool canBePointerOrHeapElementType(mlir::Type eleTy) {
+  return eleTy.isa<BoxType, BoxCharType, BoxProcType, ShapeType, ShapeShiftType,
+                   SliceType, FieldType, LenType, HeapType, PointerType,
+                   ReferenceType, TypeDescType>();
 }
 
-KindTy fir::IntegerType::getFKind() const { return getImpl()->getFKind(); }
+//===----------------------------------------------------------------------===//
+// BoxType
+//===----------------------------------------------------------------------===//
 
-// REAL
+// `box` `<` type (',' affine-map)? `>`
+mlir::Type fir::BoxType::parse(mlir::MLIRContext *context,
+                               mlir::DialectAsmParser &parser) {
+  mlir::Type ofTy;
+  if (parser.parseLess() || parser.parseType(ofTy)) {
+    parser.emitError(parser.getCurrentLocation(), "expected type parameter");
+    return {};
+  }
 
-RealType fir::RealType::get(mlir::MLIRContext *ctxt, KindTy kind) {
-  return Base::get(ctxt, kind);
+  mlir::AffineMapAttr map;
+  if (!parser.parseOptionalComma()) {
+    if (parser.parseAttribute(map)) {
+      parser.emitError(parser.getCurrentLocation(), "expected affine map");
+      return {};
+    }
+  }
+  if (parser.parseGreater()) {
+    return {};
+  }
+  return get(ofTy, map);
 }
 
-KindTy fir::RealType::getFKind() const { return getImpl()->getFKind(); }
+void fir::BoxType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getEleTy();
+  if (auto map = getLayoutMap()) {
+    printer << ", " << map;
+  }
+  printer << '>';
+}
 
 mlir::LogicalResult
-fir::BoxType::verify(llvm::function_ref<mlir::InFlightDiagnostic()>,
+fir::BoxType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
                      mlir::Type eleTy, mlir::AffineMapAttr map) {
   // TODO
   return mlir::success();
 }
 
-// Reference<T>
+//===----------------------------------------------------------------------===//
+// BoxCharType
+//===----------------------------------------------------------------------===//
 
-ReferenceType fir::ReferenceType::get(mlir::Type elementType) {
-  return Base::get(elementType.getContext(), elementType);
+mlir::Type fir::BoxCharType::parse(mlir::MLIRContext *context,
+                                   mlir::DialectAsmParser &parser) {
+  int kind = 0;
+  if (parser.parseLess() || parser.parseInteger(kind) ||
+      parser.parseGreater()) {
+    parser.emitError(parser.getCurrentLocation(), "kind value expected");
+    return {};
+  }
+  return get(context, kind);
 }
 
-mlir::Type fir::ReferenceType::getEleTy() const {
-  return getImpl()->getElementType();
+void fir::BoxCharType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getKind() << ">";
 }
 
-mlir::LogicalResult fir::ReferenceType::verify(
-    llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-    mlir::Type eleTy) {
-  if (eleTy.isa<ShapeType>() || eleTy.isa<ShapeShiftType>() ||
-      eleTy.isa<SliceType>() || eleTy.isa<FieldType>() ||
-      eleTy.isa<LenType>() || eleTy.isa<ReferenceType>() ||
-      eleTy.isa<TypeDescType>())
-    return emitError() << "cannot build a reference to type: " << eleTy << '\n';
-  return mlir::success();
+CharacterType
+fir::BoxCharType::getElementType(mlir::MLIRContext *context) const {
+  return CharacterType::getUnknownLen(context, getKind());
 }
 
-// Pointer<T>
+CharacterType fir::BoxCharType::getEleTy() const {
+  return getElementType(getContext());
+}
+
+//===----------------------------------------------------------------------===//
+// CharacterType
+//===----------------------------------------------------------------------===//
+
+// `char` `<` kind [`,` `len`] `>`
+mlir::Type fir::CharacterType::parse(mlir::MLIRContext *context,
+                                     mlir::DialectAsmParser &parser) {
+  int kind = 0;
+  if (parser.parseLess() || parser.parseInteger(kind)) {
+    parser.emitError(parser.getCurrentLocation(), "kind value expected");
+    return {};
+  }
+  CharacterType::LenType len = 1;
+  if (mlir::succeeded(parser.parseOptionalComma())) {
+    if (mlir::succeeded(parser.parseOptionalQuestion())) {
+      len = fir::CharacterType::unknownLen();
+    } else if (!mlir::succeeded(parser.parseInteger(len))) {
+      parser.emitError(parser.getCurrentLocation(), "len value expected");
+      return {};
+    }
+  }
+  if (parser.parseGreater())
+    return {};
+  return get(context, kind, len);
+}
 
-PointerType fir::PointerType::get(mlir::Type elementType) {
-  assert(singleIndirectionLevel(elementType) && "invalid element type");
-  return Base::get(elementType.getContext(), elementType);
+void fir::CharacterType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getFKind();
+  auto len = getLen();
+  if (len != fir::CharacterType::singleton()) {
+    printer << ',';
+    if (len == fir::CharacterType::unknownLen())
+      printer << '?';
+    else
+      printer << len;
+  }
+  printer << '>';
 }
 
-mlir::Type fir::PointerType::getEleTy() const {
-  return getImpl()->getElementType();
+//===----------------------------------------------------------------------===//
+// ComplexType
+//===----------------------------------------------------------------------===//
+
+mlir::Type fir::ComplexType::parse(mlir::MLIRContext *context,
+                                   mlir::DialectAsmParser &parser) {
+  return parseKindSingleton<fir::ComplexType>(parser);
 }
 
-static bool canBePointerOrHeapElementType(mlir::Type eleTy) {
-  return eleTy.isa<BoxType>() || eleTy.isa<BoxCharType>() ||
-         eleTy.isa<BoxProcType>() || eleTy.isa<ShapeType>() ||
-         eleTy.isa<ShapeShiftType>() || eleTy.isa<SliceType>() ||
-         eleTy.isa<FieldType>() || eleTy.isa<LenType>() ||
-         eleTy.isa<HeapType>() || eleTy.isa<PointerType>() ||
-         eleTy.isa<ReferenceType>() || eleTy.isa<TypeDescType>();
+void fir::ComplexType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getFKind() << '>';
 }
 
-mlir::LogicalResult fir::PointerType::verify(
-    llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-    mlir::Type eleTy) {
-  if (canBePointerOrHeapElementType(eleTy))
-    return emitError() << "cannot build a pointer to type: " << eleTy << '\n';
-  return mlir::success();
+mlir::Type fir::ComplexType::getElementType() const {
+  return fir::RealType::get(getContext(), getFKind());
 }
 
-// Heap<T>
+//===----------------------------------------------------------------------===//
+// HeapType
+//===----------------------------------------------------------------------===//
 
-HeapType fir::HeapType::get(mlir::Type elementType) {
-  assert(singleIndirectionLevel(elementType) && "invalid element type");
-  return Base::get(elementType.getContext(), elementType);
+// `heap` `<` type `>`
+mlir::Type fir::HeapType::parse(mlir::MLIRContext *context,
+                                mlir::DialectAsmParser &parser) {
+  return parseTypeSingleton<HeapType>(parser);
 }
 
-mlir::Type fir::HeapType::getEleTy() const {
-  return getImpl()->getElementType();
+void fir::HeapType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getEleTy() << '>';
 }
 
 mlir::LogicalResult
@@ -833,121 +442,190 @@ fir::HeapType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
   return mlir::success();
 }
 
-// Sequence<T>
+//===----------------------------------------------------------------------===//
+// IntegerType
+//===----------------------------------------------------------------------===//
 
-SequenceType fir::SequenceType::get(const Shape &shape, mlir::Type elementType,
-                                    mlir::AffineMapAttr map) {
-  auto *ctxt = elementType.getContext();
-  return Base::get(ctxt, shape, elementType, map);
+// `int` `<` kind `>`
+mlir::Type fir::IntegerType::parse(mlir::MLIRContext *context,
+                                   mlir::DialectAsmParser &parser) {
+  return parseKindSingleton<fir::IntegerType>(parser);
 }
 
-mlir::Type fir::SequenceType::getEleTy() const {
-  return getImpl()->getElementType();
+void fir::IntegerType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getFKind() << '>';
 }
 
-mlir::AffineMapAttr fir::SequenceType::getLayoutMap() const {
-  return getImpl()->getLayoutMap();
-}
+//===----------------------------------------------------------------------===//
+// LogicalType
+//===----------------------------------------------------------------------===//
 
-SequenceType::Shape fir::SequenceType::getShape() const {
-  return getImpl()->getShape();
+// `logical` `<` kind `>`
+mlir::Type fir::LogicalType::parse(mlir::MLIRContext *context,
+                                   mlir::DialectAsmParser &parser) {
+  return parseKindSingleton<fir::LogicalType>(parser);
 }
 
-unsigned fir::SequenceType::getConstantRows() const {
-  auto shape = getShape();
-  unsigned count = 0;
-  for (auto d : shape) {
-    if (d < 0)
-      break;
-    ++count;
-  }
-  return count;
+void fir::LogicalType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getFKind() << '>';
 }
 
-// This test helps us determine if we can degenerate an array to a
-// pointer to some interior section (possibly a single element) of the
-// sequence. This is used to determine if we can lower to the LLVM IR.
-bool fir::SequenceType::hasConstantInterior() const {
-  if (hasUnknownShape())
-    return true;
-  auto rows = getConstantRows();
-  auto dim = getDimension();
-  if (rows == dim)
-    return true;
-  auto shape = getShape();
-  for (unsigned i{rows}, size{dim}; i < size; ++i)
-    if (shape[i] != getUnknownExtent())
-      return false;
-  return true;
-}
+//===----------------------------------------------------------------------===//
+// PointerType
+//===----------------------------------------------------------------------===//
 
-mlir::LogicalResult fir::SequenceType::verify(
-    llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-    const SequenceType::Shape &shape, mlir::Type eleTy,
-    mlir::AffineMapAttr map) {
-  // DIMENSION attribute can only be applied to an intrinsic or record type
-  if (eleTy.isa<BoxType>() || eleTy.isa<BoxCharType>() ||
-      eleTy.isa<BoxProcType>() || eleTy.isa<ShapeType>() ||
-      eleTy.isa<ShapeShiftType>() || eleTy.isa<SliceType>() ||
-      eleTy.isa<FieldType>() || eleTy.isa<LenType>() || eleTy.isa<HeapType>() ||
-      eleTy.isa<PointerType>() || eleTy.isa<ReferenceType>() ||
-      eleTy.isa<TypeDescType>() || eleTy.isa<fir::VectorType>() ||
-      eleTy.isa<SequenceType>())
-    return emitError() << "cannot build an array of this element type: "
-                       << eleTy << '\n';
-  return mlir::success();
+// `ptr` `<` type `>`
+mlir::Type fir::PointerType::parse(mlir::MLIRContext *context,
+                                   mlir::DialectAsmParser &parser) {
+  return parseTypeSingleton<fir::PointerType>(parser);
 }
 
-// compare if two shapes are equivalent
-bool fir::operator==(const SequenceType::Shape &sh_1,
-                     const SequenceType::Shape &sh_2) {
-  if (sh_1.size() != sh_2.size())
-    return false;
-  auto e = sh_1.size();
-  for (decltype(e) i = 0; i != e; ++i)
-    if (sh_1[i] != sh_2[i])
-      return false;
-  return true;
+void fir::PointerType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getEleTy() << '>';
 }
 
-// compute the hash of a Shape
-llvm::hash_code fir::hash_value(const SequenceType::Shape &sh) {
-  if (sh.size()) {
-    return llvm::hash_combine_range(sh.begin(), sh.end());
-  }
-  return llvm::hash_combine(0);
+mlir::LogicalResult fir::PointerType::verify(
+    llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
+    mlir::Type eleTy) {
+  if (canBePointerOrHeapElementType(eleTy))
+    return emitError() << "cannot build a pointer to type: " << eleTy << '\n';
+  return mlir::success();
 }
 
-// Slice
+//===----------------------------------------------------------------------===//
+// RealType
+//===----------------------------------------------------------------------===//
 
-SliceType fir::SliceType::get(mlir::MLIRContext *ctxt, unsigned rank) {
-  return Base::get(ctxt, rank);
+// `real` `<` kind `>`
+mlir::Type fir::RealType::parse(mlir::MLIRContext *context,
+                                mlir::DialectAsmParser &parser) {
+  return parseKindSingleton<fir::RealType>(parser);
 }
 
-unsigned fir::SliceType::getRank() const { return getImpl()->getRank(); }
-
-/// RecordType
-///
-/// This type captures a Fortran "derived type"
-
-RecordType fir::RecordType::get(mlir::MLIRContext *ctxt, llvm::StringRef name) {
-  return Base::get(ctxt, name);
+void fir::RealType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getFKind() << '>';
 }
 
-void fir::RecordType::finalize(llvm::ArrayRef<TypePair> lenPList,
-                               llvm::ArrayRef<TypePair> typeList) {
-  getImpl()->finalize(lenPList, typeList);
+mlir::LogicalResult
+fir::RealType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
+                      KindTy fKind) {
+  // TODO
+  return mlir::success();
 }
 
-llvm::StringRef fir::RecordType::getName() { return getImpl()->getName(); }
-
-RecordType::TypeList fir::RecordType::getTypeList() {
-  return getImpl()->getTypeList();
-}
+//===----------------------------------------------------------------------===//
+// RecordType
+//===----------------------------------------------------------------------===//
 
-RecordType::TypeList fir::RecordType::getLenParamList() {
-  return getImpl()->getLenParamList();
-}
+// Fortran derived type
+// `type` `<` name
+//           (`(` id `:` type (`,` id `:` type)* `)`)?
+//           (`{` id `:` type (`,` id `:` type)* `}`)? '>'
+mlir::Type fir::RecordType::parse(mlir::MLIRContext *context,
+                                  mlir::DialectAsmParser &parser) {
+  llvm::StringRef name;
+  if (parser.parseLess() || parser.parseKeyword(&name)) {
+    parser.emitError(parser.getNameLoc(),
+                     "expected a identifier as name of derived type");
+    return {};
+  }
+  RecordType result = RecordType::get(parser.getBuilder().getContext(), name);
+
+  RecordType::TypeList lenParamList;
+  if (!parser.parseOptionalLParen()) {
+    while (true) {
+      llvm::StringRef lenparam;
+      mlir::Type intTy;
+      if (parser.parseKeyword(&lenparam) || parser.parseColon() ||
+          parser.parseType(intTy)) {
+        parser.emitError(parser.getNameLoc(), "expected LEN parameter list");
+        return {};
+      }
+      lenParamList.emplace_back(lenparam, intTy);
+      if (parser.parseOptionalComma())
+        break;
+    }
+    if (parser.parseRParen()) {
+      parser.emitError(parser.getNameLoc(), "expected ')'");
+      return {};
+    }
+  }
+
+  RecordType::TypeList typeList;
+  if (!parser.parseOptionalLBrace()) {
+    while (true) {
+      llvm::StringRef field;
+      mlir::Type fldTy;
+      if (parser.parseKeyword(&field) || parser.parseColon() ||
+          parser.parseType(fldTy)) {
+        parser.emitError(parser.getNameLoc(), "expected field type list");
+        return {};
+      }
+      typeList.emplace_back(field, fldTy);
+      if (parser.parseOptionalComma())
+        break;
+    }
+    if (parser.parseRBrace()) {
+      parser.emitError(parser.getNameLoc(), "expected '}'");
+      return {};
+    }
+  }
+
+  if (parser.parseGreater()) {
+    parser.emitError(parser.getNameLoc(), "expected '>' in type type");
+    return {};
+  }
+
+  if (lenParamList.empty() && typeList.empty())
+    return result;
+
+  result.finalize(lenParamList, typeList);
+  return verifyDerived(parser, result, lenParamList, typeList);
+}
+
+void fir::RecordType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getName();
+  if (!recordTypeVisited.count(uniqueKey())) {
+    recordTypeVisited.insert(uniqueKey());
+    if (getLenParamList().size()) {
+      char ch = '(';
+      for (auto p : getLenParamList()) {
+        printer << ch << p.first << ':';
+        p.second.print(printer.getStream());
+        ch = ',';
+      }
+      printer << ')';
+    }
+    if (getTypeList().size()) {
+      char ch = '{';
+      for (auto p : getTypeList()) {
+        printer << ch << p.first << ':';
+        p.second.print(printer.getStream());
+        ch = ',';
+      }
+      printer << '}';
+    }
+    recordTypeVisited.erase(uniqueKey());
+  }
+  printer << '>';
+}
+
+void fir::RecordType::finalize(llvm::ArrayRef<TypePair> lenPList,
+                               llvm::ArrayRef<TypePair> typeList) {
+  getImpl()->finalize(lenPList, typeList);
+}
+
+llvm::StringRef fir::RecordType::getName() const {
+  return getImpl()->getName();
+}
+
+RecordType::TypeList fir::RecordType::getTypeList() const {
+  return getImpl()->getTypeList();
+}
+
+RecordType::TypeList fir::RecordType::getLenParamList() const {
+  return getImpl()->getLenParamList();
+}
 
 detail::RecordTypeStorage const *fir::RecordType::uniqueKey() const {
   return getImpl();
@@ -968,327 +646,242 @@ mlir::Type fir::RecordType::getType(llvm::StringRef ident) {
   return {};
 }
 
+unsigned fir::RecordType::getFieldIndex(llvm::StringRef ident) {
+  for (auto f : llvm::enumerate(getTypeList()))
+    if (ident == f.value().first)
+      return f.index();
+  return std::numeric_limits<unsigned>::max();
+}
+
 //===----------------------------------------------------------------------===//
-// Type descriptor type
+// ReferenceType
 //===----------------------------------------------------------------------===//
 
-TypeDescType fir::TypeDescType::get(mlir::Type ofType) {
-  assert(!ofType.isa<ReferenceType>());
-  return Base::get(ofType.getContext(), ofType);
+// `ref` `<` type `>`
+mlir::Type fir::ReferenceType::parse(mlir::MLIRContext *context,
+                                     mlir::DialectAsmParser &parser) {
+  return parseTypeSingleton<fir::ReferenceType>(parser);
 }
 
-mlir::Type fir::TypeDescType::getOfTy() const { return getImpl()->getOfType(); }
+void fir::ReferenceType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getEleTy() << '>';
+}
 
-mlir::LogicalResult fir::TypeDescType::verify(
+mlir::LogicalResult fir::ReferenceType::verify(
     llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
     mlir::Type eleTy) {
-  if (eleTy.isa<BoxType>() || eleTy.isa<BoxCharType>() ||
-      eleTy.isa<BoxProcType>() || eleTy.isa<ShapeType>() ||
-      eleTy.isa<ShapeShiftType>() || eleTy.isa<SliceType>() ||
-      eleTy.isa<FieldType>() || eleTy.isa<LenType>() ||
-      eleTy.isa<ReferenceType>() || eleTy.isa<TypeDescType>())
-    return emitError() << "cannot build a type descriptor of type: " << eleTy
-                       << '\n';
+  if (eleTy.isa<ShapeType, ShapeShiftType, SliceType, FieldType, LenType,
+                ReferenceType, TypeDescType>())
+    return emitError() << "cannot build a reference to type: " << eleTy << '\n';
   return mlir::success();
 }
 
 //===----------------------------------------------------------------------===//
-// Vector type
+// SequenceType
 //===----------------------------------------------------------------------===//
 
-fir::VectorType fir::VectorType::get(uint64_t len, mlir::Type eleTy) {
-  return Base::get(eleTy.getContext(), len, eleTy);
+// `array` `<` `*` | bounds (`x` bounds)* `:` type (',' affine-map)? `>`
+// bounds ::= `?` | int-lit
+mlir::Type fir::SequenceType::parse(mlir::MLIRContext *context,
+                                    mlir::DialectAsmParser &parser) {
+  if (parser.parseLess()) {
+    parser.emitError(parser.getNameLoc(), "expecting '<'");
+    return {};
+  }
+  SequenceType::Shape shape;
+  if (parser.parseOptionalStar()) {
+    if (parser.parseDimensionList(shape, /*allowDynamic=*/true)) {
+      parser.emitError(parser.getNameLoc(), "invalid shape");
+      return {};
+    }
+  } else if (parser.parseColon()) {
+    parser.emitError(parser.getNameLoc(), "expected ':'");
+    return {};
+  }
+  mlir::Type eleTy;
+  if (parser.parseType(eleTy) || parser.parseGreater()) {
+    parser.emitError(parser.getNameLoc(), "expecting element type");
+    return {};
+  }
+  mlir::AffineMapAttr map;
+  if (!parser.parseOptionalComma())
+    if (parser.parseAttribute(map)) {
+      parser.emitError(parser.getNameLoc(), "expecting affine map");
+      return {};
+    }
+  return SequenceType::get(context, shape, eleTy, map);
 }
 
-mlir::Type fir::VectorType::getEleTy() const { return getImpl()->getEleTy(); }
-
-uint64_t fir::VectorType::getLen() const { return getImpl()->getLen(); }
+void fir::SequenceType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic();
+  auto shape = getShape();
+  if (shape.size()) {
+    printer << '<';
+    for (const auto &b : shape) {
+      if (b >= 0)
+        printer << b << 'x';
+      else
+        printer << "?x";
+    }
+  } else {
+    printer << "<*:";
+  }
+  printer << getEleTy();
+  if (auto map = getLayoutMap()) {
+    printer << ", ";
+    map.print(printer.getStream());
+  }
+  printer << '>';
+}
 
-mlir::LogicalResult fir::VectorType::verify(
-    llvm::function_ref<mlir::InFlightDiagnostic()> emitError, uint64_t len,
-    mlir::Type eleTy) {
-  if (!(fir::isa_real(eleTy) || fir::isa_integer(eleTy)))
-    return emitError() << "cannot build a vector of type " << eleTy << '\n';
-  return mlir::success();
+unsigned fir::SequenceType::getConstantRows() const {
+  auto shape = getShape();
+  unsigned count = 0;
+  for (auto d : shape) {
+    if (d < 0)
+      break;
+    ++count;
+  }
+  return count;
 }
 
-namespace {
+// This test helps us determine if we can degenerate an array to a
+// pointer to some interior section (possibly a single element) of the
+// sequence. This is used to determine if we can lower to the LLVM IR.
+bool fir::SequenceType::hasConstantInterior() const {
+  if (hasUnknownShape())
+    return true;
+  auto rows = getConstantRows();
+  auto dim = getDimension();
+  if (rows == dim)
+    return true;
+  auto shape = getShape();
+  for (unsigned i = rows, size = dim; i < size; ++i)
+    if (shape[i] != getUnknownExtent())
+      return false;
+  return true;
+}
 
-void printBounds(llvm::raw_ostream &os, const SequenceType::Shape &bounds) {
-  os << '<';
-  for (auto &b : bounds) {
-    if (b >= 0)
-      os << b << 'x';
-    else
-      os << "?x";
-  }
+mlir::LogicalResult fir::SequenceType::verify(
+    llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
+    llvm::ArrayRef<int64_t> shape, mlir::Type eleTy,
+    mlir::AffineMapAttr layoutMap) {
+  // DIMENSION attribute can only be applied to an intrinsic or record type
+  if (eleTy.isa<BoxType, BoxCharType, BoxProcType, ShapeType, ShapeShiftType,
+                ShiftType, SliceType, FieldType, LenType, HeapType, PointerType,
+                ReferenceType, TypeDescType, fir::VectorType, SequenceType>())
+    return emitError() << "cannot build an array of this element type: "
+                       << eleTy << '\n';
+  return mlir::success();
 }
 
-llvm::SmallPtrSet<detail::RecordTypeStorage const *, 4> recordTypeVisited;
+//===----------------------------------------------------------------------===//
+// ShapeType
+//===----------------------------------------------------------------------===//
 
-} // namespace
+mlir::Type fir::ShapeType::parse(mlir::MLIRContext *context,
+                                 mlir::DialectAsmParser &parser) {
+  return parseRankSingleton<fir::ShapeType>(parser);
+}
 
-void fir::verifyIntegralType(mlir::Type type) {
-  if (isaIntegerType(type) || type.isa<mlir::IndexType>())
-    return;
-  llvm::report_fatal_error("expected integral type");
+void fir::ShapeType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getImpl()->rank << ">";
 }
 
-void fir::printFirType(FIROpsDialect *, mlir::Type ty,
-                       mlir::DialectAsmPrinter &p) {
-  auto &os = p.getStream();
-  if (auto type = ty.dyn_cast<RecordType>()) {
-    // Fortran derived type
-    os << "type<" << type.getName();
-    if (!recordTypeVisited.count(type.uniqueKey())) {
-      recordTypeVisited.insert(type.uniqueKey());
-      if (type.getLenParamList().size()) {
-        char ch = '(';
-        for (auto p : type.getLenParamList()) {
-          os << ch << p.first << ':';
-          p.second.print(os);
-          ch = ',';
-        }
-        os << ')';
-      }
-      if (type.getTypeList().size()) {
-        char ch = '{';
-        for (auto p : type.getTypeList()) {
-          os << ch << p.first << ':';
-          p.second.print(os);
-          ch = ',';
-        }
-        os << '}';
-      }
-      recordTypeVisited.erase(type.uniqueKey());
-    }
-    os << '>';
-    return;
-  }
-  if (auto type = ty.dyn_cast<SliceType>()) {
-    os << "slice<" << type.getRank() << '>';
-    return;
-  }
-  if (auto type = ty.dyn_cast<HeapType>()) {
-    os << "heap<";
-    p.printType(type.getEleTy());
-    os << '>';
-    return;
-  }
-  if (auto type = ty.dyn_cast<fir::IntegerType>()) {
-    // Fortran intrinsic type INTEGER
-    os << "int<" << type.getFKind() << '>';
-    return;
-  }
-  if (auto type = ty.dyn_cast<LenType>()) {
-    os << "len";
-    return;
-  }
-  if (auto type = ty.dyn_cast<LogicalType>()) {
-    // Fortran intrinsic type LOGICAL
-    os << "logical<" << type.getFKind() << '>';
-    return;
-  }
-  if (auto type = ty.dyn_cast<PointerType>()) {
-    os << "ptr<";
-    p.printType(type.getEleTy());
-    os << '>';
-    return;
-  }
-  if (auto type = ty.dyn_cast<fir::RealType>()) {
-    // Fortran intrinsic types REAL and DOUBLE PRECISION
-    os << "real<" << type.getFKind() << '>';
-    return;
-  }
-  if (auto type = ty.dyn_cast<ReferenceType>()) {
-    os << "ref<";
-    p.printType(type.getEleTy());
-    os << '>';
-    return;
-  }
-  if (auto type = ty.dyn_cast<SequenceType>()) {
-    os << "array";
-    auto shape = type.getShape();
-    if (shape.size()) {
-      printBounds(os, shape);
-    } else {
-      os << "<*:";
-    }
-    p.printType(ty.cast<SequenceType>().getEleTy());
-    if (auto map = type.getLayoutMap()) {
-      os << ", ";
-      map.print(os);
-    }
-    os << '>';
-    return;
-  }
-  if (auto type = ty.dyn_cast<TypeDescType>()) {
-    os << "tdesc<";
-    p.printType(type.getOfTy());
-    os << '>';
-    return;
-  }
-  if (auto type = ty.dyn_cast<fir::VectorType>()) {
-    os << "vector<" << type.getLen() << ':';
-    p.printType(type.getEleTy());
-    os << '>';
-    return;
-  }
+//===----------------------------------------------------------------------===//
+// ShapeShiftType
+//===----------------------------------------------------------------------===//
 
-  if (mlir::succeeded(generatedTypePrinter(ty, p))) {
-    return;
-  }
+mlir::Type fir::ShapeShiftType::parse(mlir::MLIRContext *context,
+                                      mlir::DialectAsmParser &parser) {
+  return parseRankSingleton<fir::ShapeShiftType>(parser);
 }
 
-bool fir::isa_unknown_size_box(mlir::Type t) {
-  if (auto boxTy = t.dyn_cast<fir::BoxType>()) {
-    auto eleTy = boxTy.getEleTy();
-    if (auto actualEleTy = fir::dyn_cast_ptrEleTy(eleTy))
-      eleTy = actualEleTy;
-    if (eleTy.isa<mlir::NoneType>())
-      return true;
-    if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>())
-      if (seqTy.hasUnknownShape())
-        return true;
-  }
-  return false;
+void fir::ShapeShiftType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getRank() << ">";
 }
 
 //===----------------------------------------------------------------------===//
-// BoxProcType
+// ShiftType
 //===----------------------------------------------------------------------===//
 
-// `boxproc` `<` return-type `>`
-mlir::Type BoxProcType::parse(mlir::MLIRContext *context,
-                              mlir::DialectAsmParser &parser) {
-  mlir::Type ty;
-  if (parser.parseLess() || parser.parseType(ty) || parser.parseGreater()) {
-    parser.emitError(parser.getCurrentLocation(), "type expected");
-    return Type();
-  }
-  return get(context, ty);
+mlir::Type fir::ShiftType::parse(mlir::MLIRContext *context,
+                                 mlir::DialectAsmParser &parser) {
+  return parseRankSingleton<fir::ShiftType>(parser);
 }
 
-mlir::LogicalResult
-BoxProcType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-                    mlir::Type eleTy) {
-  if (eleTy.isa<mlir::FunctionType>())
-    return mlir::success();
-  if (auto refTy = eleTy.dyn_cast<ReferenceType>())
-    if (refTy.isa<mlir::FunctionType>())
-      return mlir::success();
-  return emitError() << "invalid type for boxproc" << eleTy << '\n';
+void fir::ShiftType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getRank() << ">";
 }
 
 //===----------------------------------------------------------------------===//
-// BoxType
+// SliceType
 //===----------------------------------------------------------------------===//
 
-// `box` `<` type (',' affine-map)? `>`
-mlir::Type fir::BoxType::parse(mlir::MLIRContext *context,
-                               mlir::DialectAsmParser &parser) {
-  mlir::Type ofTy;
-  if (parser.parseLess() || parser.parseType(ofTy)) {
-    parser.emitError(parser.getCurrentLocation(), "expected type parameter");
-    return Type();
-  }
-
-  mlir::AffineMapAttr map;
-  if (!parser.parseOptionalComma()) {
-    if (parser.parseAttribute(map)) {
-      parser.emitError(parser.getCurrentLocation(), "expected affine map");
-      return Type();
-    }
-  }
-  if (parser.parseGreater()) {
-    parser.emitError(parser.getCurrentLocation(), "expected '>'");
-    return Type();
-  }
-  return get(ofTy, map);
+// `slice` `<` rank `>`
+mlir::Type fir::SliceType::parse(mlir::MLIRContext *context,
+                                 mlir::DialectAsmParser &parser) {
+  return parseRankSingleton<fir::SliceType>(parser);
 }
 
-void fir::BoxType::print(::mlir::DialectAsmPrinter &printer) const {
-  printer << "box<";
-  printer.printType(getEleTy());
-  if (auto map = getLayoutMap()) {
-    printer << ", ";
-    printer.printAttribute(map);
-  }
-  printer << '>';
+void fir::SliceType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getRank() << '>';
 }
 
 //===----------------------------------------------------------------------===//
-// BoxCharType
+// TypeDescType
 //===----------------------------------------------------------------------===//
 
-mlir::Type fir::BoxCharType::parse(mlir::MLIRContext *context,
-                                   mlir::DialectAsmParser &parser) {
-  int kind = 0;
-  if (parser.parseLess() || parser.parseInteger(kind) ||
-      parser.parseGreater()) {
-    parser.emitError(parser.getCurrentLocation(), "kind value expected");
-    return Type();
-  }
-  return get(context, kind);
+// `tdesc` `<` type `>`
+mlir::Type fir::TypeDescType::parse(mlir::MLIRContext *context,
+                                    mlir::DialectAsmParser &parser) {
+  return parseTypeSingleton<fir::TypeDescType>(parser);
 }
 
-CharacterType
-fir::BoxCharType::getElementType(mlir::MLIRContext *context) const {
-  return CharacterType::getUnknownLen(context, getKind());
+void fir::TypeDescType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getOfTy() << '>';
 }
 
-CharacterType fir::BoxCharType::getEleTy() const {
-  return getElementType(getContext());
+mlir::LogicalResult fir::TypeDescType::verify(
+    llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
+    mlir::Type eleTy) {
+  if (eleTy.isa<BoxType, BoxCharType, BoxProcType, ShapeType, ShapeShiftType,
+                ShiftType, SliceType, FieldType, LenType, ReferenceType,
+                TypeDescType>())
+    return emitError() << "cannot build a type descriptor of type: " << eleTy
+                       << '\n';
+  return mlir::success();
 }
 
 //===----------------------------------------------------------------------===//
-// CharacterType
+// VectorType
 //===----------------------------------------------------------------------===//
 
-// `char` `<` kind [`,` `len`] `>`
-mlir::Type fir::CharacterType::parse(mlir::MLIRContext *context,
-                                     mlir::DialectAsmParser &parser) {
-  int kind = 0;
-  if (parser.parseLess() || parser.parseInteger(kind)) {
-    parser.emitError(parser.getCurrentLocation(), "kind value expected");
-    return Type();
-  }
-  CharacterType::LenType len = 1;
-  if (mlir::succeeded(parser.parseOptionalComma())) {
-    if (mlir::succeeded(parser.parseOptionalQuestion())) {
-      len = fir::CharacterType::unknownLen();
-    } else if (!mlir::succeeded(parser.parseInteger(len))) {
-      parser.emitError(parser.getCurrentLocation(), "len value expected");
-      return Type();
-    }
+// `vector` `<` len `:` type `>`
+mlir::Type fir::VectorType::parse(mlir::MLIRContext *context,
+                                  mlir::DialectAsmParser &parser) {
+  int64_t len = 0;
+  mlir::Type eleTy;
+  if (parser.parseLess() || parser.parseInteger(len) || parser.parseColon() ||
+      parser.parseType(eleTy) || parser.parseGreater()) {
+    parser.emitError(parser.getNameLoc(), "invalid vector type");
+    return {};
   }
-  if (parser.parseGreater())
-    return Type();
-  return get(context, kind, len);
+  return fir::VectorType::get(len, eleTy);
 }
 
-void fir::CharacterType::print(::mlir::DialectAsmPrinter &printer) const {
-  printer << "char<" << getFKind();
-  auto len = getLen();
-  if (len != fir::CharacterType::singleton()) {
-    printer << ',';
-    if (len == fir::CharacterType::unknownLen())
-      printer << '?';
-    else
-      printer << len;
-  }
-  printer << '>';
+void fir::VectorType::print(mlir::DialectAsmPrinter &printer) const {
+  printer << getMnemonic() << "<" << getLen() << ':' << getEleTy() << '>';
 }
 
-//===----------------------------------------------------------------------===//
-// ComplexType
-//===----------------------------------------------------------------------===//
-
-mlir::Type fir::ComplexType::parse(mlir::MLIRContext *context,
-                                   mlir::DialectAsmParser &parser) {
-  return parseKindSingleton<fir::ComplexType>(parser);
+mlir::LogicalResult fir::VectorType::verify(
+    llvm::function_ref<mlir::InFlightDiagnostic()> emitError, uint64_t len,
+    mlir::Type eleTy) {
+  if (!(fir::isa_real(eleTy) || fir::isa_integer(eleTy)))
+    return emitError() << "cannot build a vector of type " << eleTy << '\n';
+  return mlir::success();
 }
 
-mlir::Type fir::ComplexType::getElementType() const {
-  return fir::RealType::get(getContext(), getFKind());
+bool fir::VectorType::isValidElementType(mlir::Type t) {
+  return isa_real(t) || isa_integer(t);
 }


        


More information about the flang-commits mailing list