/* Compiler implementation of the D programming language * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/template.h */ #pragma once #include "root/root.h" #include "arraytypes.h" #include "dsymbol.h" struct OutBuffer; class Identifier; class TemplateInstance; class TemplateParameter; class TemplateTypeParameter; class TemplateThisParameter; class TemplateValueParameter; class TemplateAliasParameter; class TemplateTupleParameter; class Type; class TypeQualified; class TypeTypeof; struct Scope; class Expression; class AliasDeclaration; class FuncDeclaration; class Parameter; enum MATCH; enum PASS; class Tuple : public RootObject { public: Objects objects; // kludge for template.isType() int dyncast() const { return DYNCAST_TUPLE; } const char *toChars() { return objects.toChars(); } }; struct TemplatePrevious { TemplatePrevious *prev; Scope *sc; Objects *dedargs; }; class TemplateDeclaration : public ScopeDsymbol { public: TemplateParameters *parameters; // array of TemplateParameter's TemplateParameters *origParameters; // originals for Ddoc Expression *constraint; // Hash table to look up TemplateInstance's of this TemplateDeclaration void *instances; TemplateDeclaration *overnext; // next overloaded TemplateDeclaration TemplateDeclaration *overroot; // first in overnext list FuncDeclaration *funcroot; // first function in unified overload list Dsymbol *onemember; // if !=NULL then one member of this template bool literal; // this template declaration is a literal bool ismixin; // template declaration is only to be used as a mixin bool isstatic; // this is static template declaration Prot protection; TemplatePrevious *previous; // threaded list of previous instantiation attempts on stack TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, bool ismixin = false, bool literal = false); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); bool overloadInsert(Dsymbol *s); bool hasStaticCtorOrDtor(); const char *kind() const; const char *toChars(); Prot prot(); bool evaluateConstraint(TemplateInstance *ti, Scope *sc, Scope *paramscope, Objects *dedtypes, FuncDeclaration *fd); MATCH matchWithInstance(Scope *sc, TemplateInstance *ti, Objects *atypes, Expressions *fargs, int flag); MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs); MATCH deduceFunctionTemplateMatch(TemplateInstance *ti, Scope *sc, FuncDeclaration *&fd, Type *tthis, Expressions *fargs); RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o); FuncDeclaration *doHeaderInstantiation(TemplateInstance *ti, Scope *sc, FuncDeclaration *fd, Type *tthis, Expressions *fargs); TemplateInstance *findExistingInstance(TemplateInstance *tithis, Expressions *fargs); TemplateInstance *addInstance(TemplateInstance *ti); void removeInstance(TemplateInstance *handle); TemplateDeclaration *isTemplateDeclaration() { return this; } TemplateTupleParameter *isVariadic(); bool isOverloadable(); void accept(Visitor *v) { v->visit(this); } }; /* For type-parameter: * template Foo(ident) // specType is set to NULL * template Foo(ident : specType) * For value-parameter: * template Foo(valType ident) // specValue is set to NULL * template Foo(valType ident : specValue) * For alias-parameter: * template Foo(alias ident) * For this-parameter: * template Foo(this ident) */ class TemplateParameter { public: Loc loc; Identifier *ident; /* True if this is a part of precedent parameter specialization pattern. * * template A(T : X!TL, alias X, TL...) {} * // X and TL are dependent template parameter * * A dependent template parameter should return MATCHexact in matchArg() * to respect the match level of the corresponding precedent parameter. */ bool dependent; TemplateParameter(Loc loc, Identifier *ident); virtual TemplateTypeParameter *isTemplateTypeParameter(); virtual TemplateValueParameter *isTemplateValueParameter(); virtual TemplateAliasParameter *isTemplateAliasParameter(); virtual TemplateThisParameter *isTemplateThisParameter(); virtual TemplateTupleParameter *isTemplateTupleParameter(); virtual TemplateParameter *syntaxCopy() = 0; virtual bool declareParameter(Scope *sc) = 0; virtual bool semantic(Scope *sc, TemplateParameters *parameters) = 0; virtual void print(RootObject *oarg, RootObject *oded) = 0; virtual RootObject *specialization() = 0; virtual RootObject *defaultArg(Loc instLoc, Scope *sc) = 0; virtual bool hasDefaultArg() = 0; /* Match actual argument against parameter. */ virtual MATCH matchArg(Loc instLoc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); virtual MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0; /* Create dummy argument based on parameter. */ virtual void *dummyArg() = 0; virtual void accept(Visitor *v) { v->visit(this); } }; /* Syntax: * ident : specType = defaultType */ class TemplateTypeParameter : public TemplateParameter { using TemplateParameter::matchArg; public: Type *specType; // type parameter: if !=NULL, this is the type specialization Type *defaultType; static Type *tdummy; TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); TemplateTypeParameter *isTemplateTypeParameter(); TemplateParameter *syntaxCopy(); bool declareParameter(Scope *sc); bool semantic(Scope *sc, TemplateParameters *parameters); void print(RootObject *oarg, RootObject *oded); RootObject *specialization(); RootObject *defaultArg(Loc instLoc, Scope *sc); bool hasDefaultArg(); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); void accept(Visitor *v) { v->visit(this); } }; /* Syntax: * this ident : specType = defaultType */ class TemplateThisParameter : public TemplateTypeParameter { public: TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); TemplateThisParameter *isTemplateThisParameter(); TemplateParameter *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; /* Syntax: * valType ident : specValue = defaultValue */ class TemplateValueParameter : public TemplateParameter { using TemplateParameter::matchArg; public: Type *valType; Expression *specValue; Expression *defaultValue; static AA *edummies; TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue); TemplateValueParameter *isTemplateValueParameter(); TemplateParameter *syntaxCopy(); bool declareParameter(Scope *sc); bool semantic(Scope *sc, TemplateParameters *parameters); void print(RootObject *oarg, RootObject *oded); RootObject *specialization(); RootObject *defaultArg(Loc instLoc, Scope *sc); bool hasDefaultArg(); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); void accept(Visitor *v) { v->visit(this); } }; /* Syntax: * specType ident : specAlias = defaultAlias */ class TemplateAliasParameter : public TemplateParameter { using TemplateParameter::matchArg; public: Type *specType; RootObject *specAlias; RootObject *defaultAlias; static Dsymbol *sdummy; TemplateAliasParameter(Loc loc, Identifier *ident, Type *specType, RootObject *specAlias, RootObject *defaultAlias); TemplateAliasParameter *isTemplateAliasParameter(); TemplateParameter *syntaxCopy(); bool declareParameter(Scope *sc); bool semantic(Scope *sc, TemplateParameters *parameters); void print(RootObject *oarg, RootObject *oded); RootObject *specialization(); RootObject *defaultArg(Loc instLoc, Scope *sc); bool hasDefaultArg(); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); void accept(Visitor *v) { v->visit(this); } }; /* Syntax: * ident ... */ class TemplateTupleParameter : public TemplateParameter { public: TemplateTupleParameter(Loc loc, Identifier *ident); TemplateTupleParameter *isTemplateTupleParameter(); TemplateParameter *syntaxCopy(); bool declareParameter(Scope *sc); bool semantic(Scope *sc, TemplateParameters *parameters); void print(RootObject *oarg, RootObject *oded); RootObject *specialization(); RootObject *defaultArg(Loc instLoc, Scope *sc); bool hasDefaultArg(); MATCH matchArg(Loc loc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); void accept(Visitor *v) { v->visit(this); } }; /* Given: * foo!(args) => * name = foo * tiargs = args */ class TemplateInstance : public ScopeDsymbol { public: Identifier *name; // Array of Types/Expressions of template // instance arguments [int*, char, 10*10] Objects *tiargs; // Array of Types/Expressions corresponding // to TemplateDeclaration.parameters // [int, char, 100] Objects tdtypes; Dsymbol *tempdecl; // referenced by foo.bar.abc Dsymbol *enclosing; // if referencing local symbols, this is the context Dsymbol *aliasdecl; // !=NULL if instance is an alias for its sole member TemplateInstance *inst; // refer to existing instance ScopeDsymbol *argsym; // argument symbol table int inuse; // for recursive expansion detection int nest; // for recursive pretty printing detection bool semantictiargsdone; // has semanticTiargs() been done? bool havetempdecl; // if used second constructor bool gagged; // if the instantiation is done with error gagging hash_t hash; // cached result of toHash() Expressions *fargs; // for function template, these are the function arguments TemplateInstances* deferred; Module *memberOf; // if !null, then this TemplateInstance appears in memberOf.members[] // Used to determine the instance needs code generation. // Note that these are inaccurate until semantic analysis phase completed. TemplateInstance *tinst; // enclosing template instance TemplateInstance *tnext; // non-first instantiated instances Module *minst; // the top module that instantiated this instance TemplateInstance(Loc loc, Identifier *temp_id); TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs); static Objects *arraySyntaxCopy(Objects *objs); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc, Expressions *fargs); void semantic(Scope *sc); void semantic2(Scope *sc); void semantic3(Scope *sc); Dsymbol *toAlias(); // resolve real symbol const char *kind() const; bool oneMember(Dsymbol **ps, Identifier *ident); const char *toChars(); const char* toPrettyCharsHelper(); void printInstantiationTrace(); Identifier *getIdent(); int compare(RootObject *o); hash_t toHash(); bool needsCodegen(); // Internal bool findTempDecl(Scope *sc, WithScopeSymbol **pwithsym); bool updateTempDecl(Scope *sc, Dsymbol *s); static bool semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags); bool semanticTiargs(Scope *sc); bool findBestMatch(Scope *sc, Expressions *fargs); bool needsTypeInference(Scope *sc, int flag = 0); bool hasNestedArgs(Objects *tiargs, bool isstatic); Dsymbols *appendToModuleMember(); void declareParameters(Scope *sc); Identifier *genIdent(Objects *args); void expandMembers(Scope *sc); void tryExpandMembers(Scope *sc); void trySemantic3(Scope *sc2); TemplateInstance *isTemplateInstance() { return this; } void accept(Visitor *v) { v->visit(this); } }; class TemplateMixin : public TemplateInstance { public: TypeQualified *tqual; TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void semantic2(Scope *sc); void semantic3(Scope *sc); const char *kind() const; bool oneMember(Dsymbol **ps, Identifier *ident); int apply(Dsymbol_apply_ft_t fp, void *param); bool hasPointers(); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); const char *toChars(); bool findTempDecl(Scope *sc); TemplateMixin *isTemplateMixin() { return this; } void accept(Visitor *v) { v->visit(this); } }; Expression *isExpression(RootObject *o); Dsymbol *isDsymbol(RootObject *o); Type *isType(RootObject *o); Tuple *isTuple(RootObject *o); Parameter *isParameter(RootObject *o); bool arrayObjectIsError(Objects *args); bool isError(RootObject *o); Type *getType(RootObject *o); Dsymbol *getDsymbol(RootObject *o); RootObject *objectSyntaxCopy(RootObject *o);