text: 
  /* Compiler implementation of the D programming language
   * Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
   * written by Walter Bright
   * https://www.digitalmars.com
   * Distributed under the Boost Software License, Version 1.0.
   * https://www.boost.org/LICENSE_1_0.txt
   * https://github.com/dlang/dmd/blob/master/src/dmd/mtype.h
   */
  
  #pragma once
  
  #include "root/dcompat.h" // for d_size_t
  
  #include "arraytypes.h"
  #include "ast_node.h"
  #include "globals.h"
  #include "visitor.h"
  
  struct Scope;
  class AggregateDeclaration;
  class Identifier;
  class Expression;
  class StructDeclaration;
  class ClassDeclaration;
  class EnumDeclaration;
  class TypeInfoDeclaration;
  class Dsymbol;
  class TemplateInstance;
  class TemplateDeclaration;
  
  class TypeBasic;
  class Parameter;
  
  // Back end
  #ifdef IN_GCC
  typedef union tree_node type;
  #else
  typedef struct TYPE type;
  #endif
  
  void semanticTypeInfo(Scope *sc, Type *t);
  
  Type *typeSemantic(Type *t, const Loc &loc, Scope *sc);
  Type *merge(Type *type);
  
  enum class TY : uint8_t
  {
      Tarray,             // slice array, aka T[]
      Tsarray,            // static array, aka T[dimension]
      Taarray,            // associative array, aka T[type]
      Tpointer,
      Treference,
      Tfunction,
      Tident,
      Tclass,
      Tstruct,
      Tenum,
  
      Tdelegate,
      Tnone,
      Tvoid,
      Tint8,
      Tuns8,
      Tint16,
      Tuns16,
      Tint32,
      Tuns32,
      Tint64,
  
      Tuns64,
      Tfloat32,
      Tfloat64,
      Tfloat80,
      Timaginary32,
      Timaginary64,
      Timaginary80,
      Tcomplex32,
      Tcomplex64,
      Tcomplex80,
  
      Tbool,
      Tchar,
      Twchar,
      Tdchar,
      Terror,
      Tinstance,
      Ttypeof,
      Ttuple,
      Tslice,
      Treturn,
  
      Tnull,
      Tvector,
      Tint128,
      Tuns128,
      Ttraits,
      Tmixin,
      Tnoreturn,
      TMAX
  };
  
  #define SIZE_INVALID (~(uinteger_t)0)   // error return from size() functions
  
  
  /**
   * type modifiers
   * pick this order of numbers so switch statements work better
   */
  enum MODFlags
  {
      MODnone      = 0, // default (mutable)
      MODconst     = 1, // type is const
      MODimmutable = 4, // type is immutable
      MODshared    = 2, // type is shared
      MODwild      = 8, // type is wild
      MODwildconst = (MODwild | MODconst), // type is wild const
      MODmutable   = 0x10       // type is mutable (only used in wildcard matching)
  };
  typedef unsigned char MOD;
  
  enum VarArgValues
  {
      VARARGnone     = 0,  /// fixed number of arguments
      VARARGvariadic = 1,  /// T t, ...)  can be C-style (core.stdc.stdarg) or D-style (core.vararg)
      VARARGtypesafe = 2   /// T t ...) typesafe https://dlang.org/spec/function.html#typesafe_variadic_functions
                           ///   or https://dlang.org/spec/function.html#typesafe_variadic_functions
  };
  typedef unsigned char VarArg;
  
  class Type : public ASTNode
  {
  public:
      TY ty;
      MOD mod;  // modifiers MODxxxx
      char *deco;
  
  private:
      void* mcache;
  
  public:
      Type *pto;          // merged pointer to this type
      Type *rto;          // reference to this type
      Type *arrayof;      // array of this type
      TypeInfoDeclaration *vtinfo;        // TypeInfo object for this Type
  
      type *ctype;        // for back end
  
      static Type *tvoid;
      static Type *tint8;
      static Type *tuns8;
      static Type *tint16;
      static Type *tuns16;
      static Type *tint32;
      static Type *tuns32;
      static Type *tint64;
      static Type *tuns64;
      static Type *tint128;
      static Type *tuns128;
      static Type *tfloat32;
      static Type *tfloat64;
      static Type *tfloat80;
  
      static Type *timaginary32;
      static Type *timaginary64;
      static Type *timaginary80;
  
      static Type *tcomplex32;
      static Type *tcomplex64;
      static Type *tcomplex80;
  
      static Type *tbool;
      static Type *tchar;
      static Type *twchar;
      static Type *tdchar;
  
      // Some special types
      static Type *tshiftcnt;
      static Type *tvoidptr;              // void*
      static Type *tstring;               // immutable(char)[]
      static Type *twstring;              // immutable(wchar)[]
      static Type *tdstring;              // immutable(dchar)[]
      static Type *terror;                // for error recovery
      static Type *tnull;                 // for null type
      static Type *tnoreturn;             // for bottom type typeof(*null)
  
      static Type *tsize_t;               // matches size_t alias
      static Type *tptrdiff_t;            // matches ptrdiff_t alias
      static Type *thash_t;               // matches hash_t alias
  
      static ClassDeclaration *dtypeinfo;
      static ClassDeclaration *typeinfoclass;
      static ClassDeclaration *typeinfointerface;
      static ClassDeclaration *typeinfostruct;
      static ClassDeclaration *typeinfopointer;
      static ClassDeclaration *typeinfoarray;
      static ClassDeclaration *typeinfostaticarray;
      static ClassDeclaration *typeinfoassociativearray;
      static ClassDeclaration *typeinfovector;
      static ClassDeclaration *typeinfoenum;
      static ClassDeclaration *typeinfofunction;
      static ClassDeclaration *typeinfodelegate;
      static ClassDeclaration *typeinfotypelist;
      static ClassDeclaration *typeinfoconst;
      static ClassDeclaration *typeinfoinvariant;
      static ClassDeclaration *typeinfoshared;
      static ClassDeclaration *typeinfowild;
  
      static TemplateDeclaration *rtinfo;
  
      static Type *basic[(int)TY::TMAX];
  
      virtual const char *kind();
      Type *copy() const;
      virtual Type *syntaxCopy();
      bool equals(const RootObject *o) const override;
      bool equivalent(Type *t);
      // kludge for template.isType()
      DYNCAST dyncast() const override final { return DYNCAST_TYPE; }
      size_t getUniqueID() const;
      const char *toChars() const override;
      char *toPrettyChars(bool QualifyTypes = false);
      static void _init();
  
      uinteger_t size();
      virtual uinteger_t size(const Loc &loc);
      virtual unsigned alignsize();
      Type *trySemantic(const Loc &loc, Scope *sc);
      Type *merge2();
      void modToBuffer(OutBuffer *buf) const;
      char *modToChars() const;
  
      virtual bool isintegral();
      virtual bool isfloating();   // real, imaginary, or complex
      virtual bool isreal();
      virtual bool isimaginary();
      virtual bool iscomplex();
      virtual bool isscalar();
      virtual bool isunsigned();
      virtual bool isscope();
      virtual bool isString();
      virtual bool isAssignable();
      virtual bool isBoolean();
      virtual void checkDeprecated(const Loc &loc, Scope *sc);
      bool isConst() const       { return (mod & MODconst) != 0; }
      bool isImmutable() const   { return (mod & MODimmutable) != 0; }
      bool isMutable() const     { return (mod & (MODconst | MODimmutable | MODwild)) == 0; }
      bool isShared() const      { return (mod & MODshared) != 0; }
      bool isSharedConst() const { return (mod & (MODshared | MODconst)) == (MODshared | MODconst); }
      bool isWild() const        { return (mod & MODwild) != 0; }
      bool isWildConst() const   { return (mod & MODwildconst) == MODwildconst; }
      bool isSharedWild() const  { return (mod & (MODshared | MODwild)) == (MODshared | MODwild); }
      bool isNaked() const       { return mod == 0; }
      Type *nullAttributes() const;
      Type *constOf();
      Type *immutableOf();
      Type *mutableOf();
      Type *sharedOf();
      Type *sharedConstOf();
      Type *unSharedOf();
      Type *wildOf();
      Type *wildConstOf();
      Type *sharedWildOf();
      Type *sharedWildConstOf();
      void fixTo(Type *t);
      void check();
      Type *addSTC(StorageClass stc);
      Type *castMod(MOD mod);
      Type *addMod(MOD mod);
      virtual Type *addStorageClass(StorageClass stc);
      Type *pointerTo();
      Type *referenceTo();
      Type *arrayOf();
      Type *sarrayOf(dinteger_t dim);
      bool hasDeprecatedAliasThis();
      Type *aliasthisOf();
      virtual Type *makeConst();
      virtual Type *makeImmutable();
      virtual Type *makeShared();
      virtual Type *makeSharedConst();
      virtual Type *makeWild();
      virtual Type *makeWildConst();
      virtual Type *makeSharedWild();
      virtual Type *makeSharedWildConst();
      virtual Type *makeMutable();
      virtual Dsymbol *toDsymbol(Scope *sc);
      Type *toBasetype();
      virtual bool isBaseOf(Type *t, int *poffset);
      virtual MATCH implicitConvTo(Type *to);
      virtual MATCH constConv(Type *to);
      virtual unsigned char deduceWild(Type *t, bool isRef);
      virtual Type *substWildTo(unsigned mod);
  
      Type *unqualify(unsigned m);
  
      virtual Type *toHeadMutable();
      virtual ClassDeclaration *isClassHandle();
      virtual structalign_t alignment();
      virtual Expression *defaultInitLiteral(const Loc &loc);
      virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0
      Identifier *getTypeInfoIdent();
      virtual int hasWild() const;
      virtual bool hasPointers();
      virtual bool hasVoidInitPointers();
      virtual bool hasInvariant();
      virtual Type *nextOf();
      Type *baseElemOf();
      uinteger_t sizemask();
      virtual bool needsDestruction();
      virtual bool needsCopyOrPostblit();
      virtual bool needsNested();
  
      TypeFunction *toTypeFunction();
  
      // For eliminating dynamic_cast
      virtual TypeBasic *isTypeBasic();
      TypeFunction *isPtrToFunction();
      TypeFunction *isFunction_Delegate_PtrToFunction();
      TypeError *isTypeError();
      TypeVector *isTypeVector();
      TypeSArray *isTypeSArray();
      TypeDArray *isTypeDArray();
      TypeAArray *isTypeAArray();
      TypePointer *isTypePointer();
      TypeReference *isTypeReference();
      TypeFunction *isTypeFunction();
      TypeDelegate *isTypeDelegate();
      TypeIdentifier *isTypeIdentifier();
      TypeInstance *isTypeInstance();
      TypeTypeof *isTypeTypeof();
      TypeReturn *isTypeReturn();
      TypeStruct *isTypeStruct();
      TypeEnum *isTypeEnum();
      TypeClass *isTypeClass();
      TypeTuple *isTypeTuple();
      TypeSlice *isTypeSlice();
      TypeNull *isTypeNull();
      TypeMixin *isTypeMixin();
      TypeTraits *isTypeTraits();
      TypeNoreturn *isTypeNoreturn();
      TypeTag *isTypeTag();
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeError final : public Type
  {
  public:
      const char *kind() override;
      TypeError *syntaxCopy() override;
  
      uinteger_t size(const Loc &loc) override;
      Expression *defaultInitLiteral(const Loc &loc) override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeNext : public Type
  {
  public:
      Type *next;
  
      void checkDeprecated(const Loc &loc, Scope *sc) override final;
      int hasWild() const override final;
      Type *nextOf() override final;
      Type *makeConst() override final;
      Type *makeImmutable() override final;
      Type *makeShared() override final;
      Type *makeSharedConst() override final;
      Type *makeWild() override final;
      Type *makeWildConst() override final;
      Type *makeSharedWild() override final;
      Type *makeSharedWildConst() override final;
      Type *makeMutable() override final;
      MATCH constConv(Type *to) override;
      unsigned char deduceWild(Type *t, bool isRef) override final;
      void transitive();
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeBasic final : public Type
  {
  public:
      const char *dstring;
      unsigned flags;
  
      const char *kind() override;
      TypeBasic *syntaxCopy() override;
      uinteger_t size(const Loc &loc) override;
      unsigned alignsize() override;
      bool isintegral() override;
      bool isfloating() override;
      bool isreal() override;
      bool isimaginary() override;
      bool iscomplex() override;
      bool isscalar() override;
      bool isunsigned() override;
      MATCH implicitConvTo(Type *to) override;
      bool isZeroInit(const Loc &loc) override;
  
      // For eliminating dynamic_cast
      TypeBasic *isTypeBasic() override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeVector final : public Type
  {
  public:
      Type *basetype;
  
      static TypeVector *create(Type *basetype);
      const char *kind() override;
      TypeVector *syntaxCopy() override;
      uinteger_t size(const Loc &loc) override;
      unsigned alignsize() override;
      bool isintegral() override;
      bool isfloating() override;
      bool isscalar() override;
      bool isunsigned() override;
      bool isBoolean() override;
      MATCH implicitConvTo(Type *to) override;
      Expression *defaultInitLiteral(const Loc &loc) override;
      TypeBasic *elementType();
      bool isZeroInit(const Loc &loc) override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeArray : public TypeNext
  {
  public:
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  // Static array, one with a fixed dimension
  class TypeSArray final : public TypeArray
  {
  public:
      Expression *dim;
  
      const char *kind() override;
      TypeSArray *syntaxCopy() override;
      bool isIncomplete();
      uinteger_t size(const Loc &loc) override;
      unsigned alignsize() override;
      bool isString() override;
      bool isZeroInit(const Loc &loc) override;
      structalign_t alignment() override;
      MATCH constConv(Type *to) override;
      MATCH implicitConvTo(Type *to) override;
      Expression *defaultInitLiteral(const Loc &loc) override;
      bool hasPointers() override;
      bool hasInvariant() override;
      bool needsDestruction() override;
      bool needsCopyOrPostblit() override;
      bool needsNested() override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  // Dynamic array, no dimension
  class TypeDArray final : public TypeArray
  {
  public:
      const char *kind() override;
      TypeDArray *syntaxCopy() override;
      uinteger_t size(const Loc &loc) override;
      unsigned alignsize() override;
      bool isString() override;
      bool isZeroInit(const Loc &loc) override;
      bool isBoolean() override;
      MATCH implicitConvTo(Type *to) override;
      bool hasPointers() override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeAArray final : public TypeArray
  {
  public:
      Type *index;                // key type
      Loc loc;
  
      static TypeAArray *create(Type *t, Type *index);
      const char *kind() override;
      TypeAArray *syntaxCopy() override;
      uinteger_t size(const Loc &loc) override;
      bool isZeroInit(const Loc &loc) override;
      bool isBoolean() override;
      bool hasPointers() override;
      MATCH implicitConvTo(Type *to) override;
      MATCH constConv(Type *to) override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypePointer final : public TypeNext
  {
  public:
      static TypePointer *create(Type *t);
      const char *kind() override;
      TypePointer *syntaxCopy() override;
      uinteger_t size(const Loc &loc) override;
      MATCH implicitConvTo(Type *to) override;
      MATCH constConv(Type *to) override;
      bool isscalar() override;
      bool isZeroInit(const Loc &loc) override;
      bool hasPointers() override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeReference final : public TypeNext
  {
  public:
      const char *kind() override;
      TypeReference *syntaxCopy() override;
      uinteger_t size(const Loc &loc) override;
      bool isZeroInit(const Loc &loc) override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  enum RET
  {
      RETregs     = 1,    // returned in registers
      RETstack    = 2     // returned on stack
  };
  
  enum class TRUST : unsigned char
  {
      default_ = 0,
      system = 1,    // @system (same as TRUSTdefault)
      trusted = 2,   // @trusted
      safe = 3       // @safe
  };
  
  enum TRUSTformat
  {
      TRUSTformatDefault,  // do not emit @system when trust == TRUSTdefault
      TRUSTformatSystem    // emit @system when trust == TRUSTdefault
  };
  
  enum class PURE : unsigned char
  {
      impure = 0,     // not pure at all
      fwdref = 1,     // it's pure, but not known which level yet
      weak = 2,       // no mutable globals are read or written
      const_ = 3,     // parameters are values or const
  };
  
  class Parameter final : public ASTNode
  {
  public:
      StorageClass storageClass;
      Type *type;
      Identifier *ident;
      Expression *defaultArg;
      UserAttributeDeclaration *userAttribDecl;   // user defined attributes
  
      static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident,
                               Expression *defaultArg, UserAttributeDeclaration *userAttribDecl);
      Parameter *syntaxCopy();
      Type *isLazyArray();
      // kludge for template.isType()
      DYNCAST dyncast() const override { return DYNCAST_PARAMETER; }
      void accept(Visitor *v) override { v->visit(this); }
  
      static size_t dim(Parameters *parameters);
      static Parameter *getNth(Parameters *parameters, d_size_t nth);
      const char *toChars() const override;
      bool isCovariant(bool returnByRef, const Parameter *p, bool previewIn) const;
  };
  
  struct ParameterList
  {
      Parameters* parameters;
      StorageClass stc;
      VarArg varargs;
      bool hasIdentifierList; // true if C identifier-list style
  
      size_t length();
      Parameter *operator[](size_t i) { return Parameter::getNth(parameters, i); }
  };
  
  class TypeFunction final : public TypeNext
  {
  public:
      // .next is the return type
  
      ParameterList parameterList; // function parameters
      uint16_t bitFields;
      LINK linkage;                // calling convention
      TRUST trust;                 // level of trust
      PURE purity;                 // PURExxxx
      char inuse;
      Expressions *fargs;          // function arguments
  
      static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0);
      const char *kind() override;
      TypeFunction *syntaxCopy() override;
      void purityLevel();
      bool hasLazyParameters();
      bool isDstyleVariadic() const;
      StorageClass parameterStorageClass(Parameter *p);
      Type *addStorageClass(StorageClass stc) override;
  
      Type *substWildTo(unsigned mod) override;
      MATCH constConv(Type *to) override;
  
      bool isnothrow() const;
      void isnothrow(bool v);
      bool isnogc() const;
      void isnogc(bool v);
      bool isproperty() const;
      void isproperty(bool v);
      bool isref() const;
      void isref(bool v);
      bool isreturn() const;
      void isreturn(bool v);
      bool isreturnscope() const;
      void isreturnscope(bool v);
      bool isScopeQual() const;
      void isScopeQual(bool v);
      bool isreturninferred() const;
      void isreturninferred(bool v);
      bool isscopeinferred() const;
      void isscopeinferred(bool v);
      bool islive() const;
      void islive(bool v);
      bool incomplete() const;
      void incomplete(bool v);
      bool isInOutParam() const;
      void isInOutParam(bool v);
      bool isInOutQual() const;
      void isInOutQual(bool v);
      bool iswild() const;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeDelegate final : public TypeNext
  {
  public:
      // .next is a TypeFunction
  
      static TypeDelegate *create(TypeFunction *t);
      const char *kind() override;
      TypeDelegate *syntaxCopy() override;
      Type *addStorageClass(StorageClass stc) override;
      uinteger_t size(const Loc &loc) override;
      unsigned alignsize() override;
      MATCH implicitConvTo(Type *to) override;
      bool isZeroInit(const Loc &loc) override;
      bool isBoolean() override;
      bool hasPointers() override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeTraits final : public Type
  {
      Loc loc;
      /// The expression to resolve as type or symbol.
      TraitsExp *exp;
      /// Cached type/symbol after semantic analysis.
      RootObject *obj;
  
      const char *kind() override;
      TypeTraits *syntaxCopy() override;
      uinteger_t size(const Loc &loc) override;
      Dsymbol *toDsymbol(Scope *sc) override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeMixin final : public Type
  {
      Loc loc;
      Expressions *exps;
      RootObject *obj;
  
      const char *kind() override;
      TypeMixin *syntaxCopy() override;
      Dsymbol *toDsymbol(Scope *sc) override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeQualified : public Type
  {
  public:
      Loc loc;
      // array of Identifier and TypeInstance,
      // representing ident.ident!tiargs.ident. ... etc.
      Objects idents;
  
      void syntaxCopyHelper(TypeQualified *t);
      void addIdent(Identifier *ident);
      void addInst(TemplateInstance *inst);
      void addIndex(RootObject *expr);
      uinteger_t size(const Loc &loc) override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeIdentifier final : public TypeQualified
  {
  public:
      Identifier *ident;
      Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution
  
      static TypeIdentifier *create(const Loc &loc, Identifier *ident);
      const char *kind() override;
      TypeIdentifier *syntaxCopy() override;
      Dsymbol *toDsymbol(Scope *sc) override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  /* Similar to TypeIdentifier, but with a TemplateInstance as the root
   */
  class TypeInstance final : public TypeQualified
  {
  public:
      TemplateInstance *tempinst;
  
      const char *kind() override;
      TypeInstance *syntaxCopy() override;
      Dsymbol *toDsymbol(Scope *sc) override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeTypeof final : public TypeQualified
  {
  public:
      Expression *exp;
      int inuse;
  
      const char *kind() override;
      TypeTypeof *syntaxCopy() override;
      Dsymbol *toDsymbol(Scope *sc) override;
      uinteger_t size(const Loc &loc) override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeReturn final : public TypeQualified
  {
  public:
      const char *kind() override;
      TypeReturn *syntaxCopy() override;
      Dsymbol *toDsymbol(Scope *sc) override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  // Whether alias this dependency is recursive or not.
  enum AliasThisRec
  {
      RECno = 0,      // no alias this recursion
      RECyes = 1,     // alias this has recursive dependency
      RECfwdref = 2,  // not yet known
      RECtypeMask = 3,// mask to read no/yes/fwdref
  
      RECtracing = 0x4, // mark in progress of implicitConvTo/deduceWild
      RECtracingDT = 0x8  // mark in progress of deduceType
  };
  
  class TypeStruct final : public Type
  {
  public:
      StructDeclaration *sym;
      AliasThisRec att;
      bool inuse;
  
      static TypeStruct *create(StructDeclaration *sym);
      const char *kind() override;
      uinteger_t size(const Loc &loc) override;
      unsigned alignsize() override;
      TypeStruct *syntaxCopy() override;
      Dsymbol *toDsymbol(Scope *sc) override;
      structalign_t alignment() override;
      Expression *defaultInitLiteral(const Loc &loc) override;
      bool isZeroInit(const Loc &loc) override;
      bool isAssignable() override;
      bool isBoolean() override;
      bool needsDestruction() override;
      bool needsCopyOrPostblit() override;
      bool needsNested() override;
      bool hasPointers() override;
      bool hasVoidInitPointers() override;
      bool hasInvariant() override;
      MATCH implicitConvTo(Type *to) override;
      MATCH constConv(Type *to) override;
      unsigned char deduceWild(Type *t, bool isRef) override;
      Type *toHeadMutable() override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeEnum final : public Type
  {
  public:
      EnumDeclaration *sym;
  
      const char *kind() override;
      TypeEnum *syntaxCopy() override;
      uinteger_t size(const Loc &loc) override;
      unsigned alignsize() override;
      Type *memType(const Loc &loc = Loc());
      Dsymbol *toDsymbol(Scope *sc) override;
      bool isintegral() override;
      bool isfloating() override;
      bool isreal() override;
      bool isimaginary() override;
      bool iscomplex() override;
      bool isscalar() override;
      bool isunsigned() override;
      bool isBoolean() override;
      bool isString() override;
      bool isAssignable() override;
      bool needsDestruction() override;
      bool needsCopyOrPostblit() override;
      bool needsNested() override;
      MATCH implicitConvTo(Type *to) override;
      MATCH constConv(Type *to) override;
      bool isZeroInit(const Loc &loc) override;
      bool hasPointers() override;
      bool hasVoidInitPointers() override;
      bool hasInvariant() override;
      Type *nextOf() override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeClass final : public Type
  {
  public:
      ClassDeclaration *sym;
      AliasThisRec att;
      CPPMANGLE cppmangle;
  
      const char *kind() override;
      uinteger_t size(const Loc &loc) override;
      TypeClass *syntaxCopy() override;
      Dsymbol *toDsymbol(Scope *sc) override;
      ClassDeclaration *isClassHandle() override;
      bool isBaseOf(Type *t, int *poffset) override;
      MATCH implicitConvTo(Type *to) override;
      MATCH constConv(Type *to) override;
      unsigned char deduceWild(Type *t, bool isRef) override;
      Type *toHeadMutable() override;
      bool isZeroInit(const Loc &loc) override;
      bool isscope() override;
      bool isBoolean() override;
      bool hasPointers() override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeTuple final : public Type
  {
  public:
      // 'logically immutable' cached global - don't modify (neither pointer nor pointee)!
      static TypeTuple *empty;
  
      Parameters *arguments;      // types making up the tuple
  
      static TypeTuple *create(Parameters *arguments);
      static TypeTuple *create();
      static TypeTuple *create(Type *t1);
      static TypeTuple *create(Type *t1, Type *t2);
      const char *kind() override;
      TypeTuple *syntaxCopy() override;
      bool equals(const RootObject *o) const override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeSlice final : public TypeNext
  {
  public:
      Expression *lwr;
      Expression *upr;
  
      const char *kind() override;
      TypeSlice *syntaxCopy() override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeNull final : public Type
  {
  public:
      const char *kind() override;
  
      TypeNull *syntaxCopy() override;
      MATCH implicitConvTo(Type *to) override;
      bool hasPointers() override;
      bool isBoolean() override;
  
      uinteger_t size(const Loc &loc) override;
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeNoreturn final : public Type
  {
  public:
      const char *kind() override;
      TypeNoreturn *syntaxCopy() override;
      MATCH implicitConvTo(Type* to) override;
      MATCH constConv(Type* to) override;
      bool isBoolean() override;
      uinteger_t size(const Loc& loc) override;
      unsigned alignsize() override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  class TypeTag final : public Type
  {
  public:
      TypeTag *syntaxCopy() override;
  
      void accept(Visitor *v) override { v->visit(this); }
  };
  
  /**************************************************************/
  
  bool arrayTypeCompatibleWithoutCasting(Type *t1, Type *t2);
  
  // If the type is a class or struct, returns the symbol for it, else null.
  AggregateDeclaration *isAggregate(Type *t);
  