diff options
Diffstat (limited to 'gcc/d/dmd/dtemplate.c')
-rw-r--r-- | gcc/d/dmd/dtemplate.c | 7581 |
1 files changed, 0 insertions, 7581 deletions
diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c deleted file mode 100644 index 20036f2dbff..00000000000 --- a/gcc/d/dmd/dtemplate.c +++ /dev/null @@ -1,7581 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (C) 1999-2021 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/D-Programming-Language/dmd/blob/master/src/template.c - */ - -// Handle template implementation - -#include "root/dsystem.h" -#include "root/root.h" -#include "root/aav.h" -#include "root/rmem.h" -#include "root/stringtable.h" -#include "root/hash.h" - -#include "mangle.h" -#include "mtype.h" -#include "template.h" -#include "init.h" -#include "expression.h" -#include "scope.h" -#include "module.h" -#include "aggregate.h" -#include "declaration.h" -#include "dsymbol.h" -#include "mars.h" -#include "dsymbol.h" -#include "identifier.h" -#include "hdrgen.h" -#include "id.h" -#include "attrib.h" -#include "cond.h" -#include "tokens.h" - -#define IDX_NOTFOUND (0x12345678) // index is not found - -Type *rawTypeMerge(Type *t1, Type *t2); -bool MODimplicitConv(MOD modfrom, MOD modto); -MATCH MODmethodConv(MOD modfrom, MOD modto); -MOD MODmerge(MOD mod1, MOD mod2); - -static size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters); -static int arrayObjectMatch(Objects *oa1, Objects *oa2); -static unsigned char deduceWildHelper(Type *t, Type **at, Type *tparam); -static MATCH deduceTypeHelper(Type *t, Type **at, Type *tparam); -bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0); -bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors); - -/******************************************** - * These functions substitute for dynamic_cast. dynamic_cast does not work - * on earlier versions of gcc. - */ - -Expression *isExpression(RootObject *o) -{ - //return dynamic_cast<Expression *>(o); - if (!o || o->dyncast() != DYNCAST_EXPRESSION) - return NULL; - return (Expression *)o; -} - -Dsymbol *isDsymbol(RootObject *o) -{ - //return dynamic_cast<Dsymbol *>(o); - if (!o || o->dyncast() != DYNCAST_DSYMBOL) - return NULL; - return (Dsymbol *)o; -} - -Type *isType(RootObject *o) -{ - //return dynamic_cast<Type *>(o); - if (!o || o->dyncast() != DYNCAST_TYPE) - return NULL; - return (Type *)o; -} - -Tuple *isTuple(RootObject *o) -{ - //return dynamic_cast<Tuple *>(o); - if (!o || o->dyncast() != DYNCAST_TUPLE) - return NULL; - return (Tuple *)o; -} - -Parameter *isParameter(RootObject *o) -{ - //return dynamic_cast<Parameter *>(o); - if (!o || o->dyncast() != DYNCAST_PARAMETER) - return NULL; - return (Parameter *)o; -} - -/************************************** - * Is this Object an error? - */ -bool isError(RootObject *o) -{ - Type *t = isType(o); - if (t) - return (t->ty == Terror); - Expression *e = isExpression(o); - if (e) - return (e->op == TOKerror || !e->type || e->type->ty == Terror); - Tuple *v = isTuple(o); - if (v) - return arrayObjectIsError(&v->objects); - Dsymbol *s = isDsymbol(o); - assert(s); - if (s->errors) - return true; - return s->parent ? isError(s->parent) : false; -} - -/************************************** - * Are any of the Objects an error? - */ -bool arrayObjectIsError(Objects *args) -{ - for (size_t i = 0; i < args->length; i++) - { - RootObject *o = (*args)[i]; - if (isError(o)) - return true; - } - return false; -} - -/*********************** - * Try to get arg as a type. - */ - -Type *getType(RootObject *o) -{ - Type *t = isType(o); - if (!t) - { - Expression *e = isExpression(o); - if (e) - t = e->type; - } - return t; -} - -Dsymbol *getDsymbol(RootObject *oarg) -{ - //printf("getDsymbol()\n"); - //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg)); - - Dsymbol *sa; - Expression *ea = isExpression(oarg); - if (ea) - { - // Try to convert Expression to symbol - if (VarExp *ve = ea->isVarExp()) - sa = ve->var; - else if (FuncExp *fe = ea->isFuncExp()) - sa = fe->td ? (Dsymbol *)fe->td : (Dsymbol *)fe->fd; - else if (TemplateExp *te = ea->isTemplateExp()) - sa = te->td; - else if (ScopeExp *se = ea->isScopeExp()) - sa = se->sds; - else - sa = NULL; - } - else - { - // Try to convert Type to symbol - Type *ta = isType(oarg); - if (ta) - sa = ta->toDsymbol(NULL); - else - sa = isDsymbol(oarg); // if already a symbol - } - return sa; -} - -/*********************** - * Try to get value from manifest constant - */ - -static Expression *getValue(Expression *e) -{ - if (e && e->op == TOKvar) - { - VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); - if (v && v->storage_class & STCmanifest) - { - e = v->getConstInitializer(); - } - } - return e; -} - -static Expression *getValue(Dsymbol *&s) -{ - Expression *e = NULL; - if (s) - { - VarDeclaration *v = s->isVarDeclaration(); - if (v && v->storage_class & STCmanifest) - { - e = v->getConstInitializer(); - } - } - return e; -} - -/********************************** - * Return true if e could be valid only as a template value parameter. - * Return false if it might be an alias or tuple. - * (Note that even in this case, it could still turn out to be a value). - */ -bool definitelyValueParameter(Expression *e) -{ - // None of these can be value parameters - if (e->op == TOKtuple || e->op == TOKscope || - e->op == TOKtype || e->op == TOKdottype || - e->op == TOKtemplate || e->op == TOKdottd || - e->op == TOKfunction || e->op == TOKerror || - e->op == TOKthis || e->op == TOKsuper || - e->op == TOKdot) - return false; - - if (e->op != TOKdotvar) - return true; - - /* Template instantiations involving a DotVar expression are difficult. - * In most cases, they should be treated as a value parameter, and interpreted. - * But they might also just be a fully qualified name, which should be treated - * as an alias. - */ - - // x.y.f cannot be a value - FuncDeclaration *f = ((DotVarExp *)e)->var->isFuncDeclaration(); - if (f) - return false; - - while (e->op == TOKdotvar) - { - e = ((DotVarExp *)e)->e1; - } - // this.x.y and super.x.y couldn't possibly be valid values. - if (e->op == TOKthis || e->op == TOKsuper) - return false; - - // e.type.x could be an alias - if (e->op == TOKdottype) - return false; - - // var.x.y is the only other possible form of alias - if (e->op != TOKvar) - return true; - - VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); - - // func.x.y is not an alias - if (!v) - return true; - - // TODO: Should we force CTFE if it is a global constant? - - return false; -} - -static Expression *getExpression(RootObject *o) -{ - Dsymbol *s = isDsymbol(o); - return s ? getValue(s) : getValue(isExpression(o)); -} - -/****************************** - * If o1 matches o2, return true. - * Else, return false. - */ - -static bool match(RootObject *o1, RootObject *o2) -{ - //printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n", - // o1, o1->toChars(), o1->dyncast(), o2, o2->toChars(), o2->dyncast()); - - /* A proper implementation of the various equals() overrides - * should make it possible to just do o1->equals(o2), but - * we'll do that another day. - */ - - /* Manifest constants should be compared by their values, - * at least in template arguments. - */ - - if (Type *t1 = isType(o1)) - { - Type *t2 = isType(o2); - if (!t2) - goto Lnomatch; - - //printf("\tt1 = %s\n", t1->toChars()); - //printf("\tt2 = %s\n", t2->toChars()); - if (!t1->equals(t2)) - goto Lnomatch; - - goto Lmatch; - } - if (Expression *e1 = getExpression(o1)) - { - Expression *e2 = getExpression(o2); - if (!e2) - goto Lnomatch; - - //printf("\te1 = %s %s %s\n", e1->type->toChars(), Token::toChars(e1->op), e1->toChars()); - //printf("\te2 = %s %s %s\n", e2->type->toChars(), Token::toChars(e2->op), e2->toChars()); - - // two expressions can be equal although they do not have the same - // type; that happens when they have the same value. So check type - // as well as expression equality to ensure templates are properly - // matched. - if (!e1->type->equals(e2->type) || !e1->equals(e2)) - goto Lnomatch; - - goto Lmatch; - } - if (Dsymbol *s1 = isDsymbol(o1)) - { - Dsymbol *s2 = isDsymbol(o2); - if (!s2) - goto Lnomatch; - - //printf("\ts1 = %s\n", s1->toChars()); - //printf("\ts2 = %s\n", s2->toChars()); - if (!s1->equals(s2)) - goto Lnomatch; - if (s1->parent != s2->parent && !s1->isFuncDeclaration() && !s2->isFuncDeclaration()) - goto Lnomatch; - - goto Lmatch; - } - if (Tuple *u1 = isTuple(o1)) - { - Tuple *u2 = isTuple(o2); - if (!u2) - goto Lnomatch; - - //printf("\tu1 = %s\n", u1->toChars()); - //printf("\tu2 = %s\n", u2->toChars()); - if (!arrayObjectMatch(&u1->objects, &u2->objects)) - goto Lnomatch; - - goto Lmatch; - } -Lmatch: - //printf("\t-> match\n"); - return true; - -Lnomatch: - //printf("\t-> nomatch\n"); - return false; -} - - -/************************************ - * Match an array of them. - */ -int arrayObjectMatch(Objects *oa1, Objects *oa2) -{ - if (oa1 == oa2) - return 1; - if (oa1->length != oa2->length) - return 0; - for (size_t j = 0; j < oa1->length; j++) - { - RootObject *o1 = (*oa1)[j]; - RootObject *o2 = (*oa2)[j]; - if (!match(o1, o2)) - { - return 0; - } - } - return 1; -} - - -/************************************ - * Computes hash of expression. - * Handles all Expression classes and MUST match their equals method, - * i.e. e1->equals(e2) implies expressionHash(e1) == expressionHash(e2). - */ -static hash_t expressionHash(Expression *e) -{ - switch (e->op) - { - case TOKint64: - return (size_t) ((IntegerExp *)e)->getInteger(); - - case TOKfloat64: - return CTFloat::hash(((RealExp *)e)->value); - - case TOKcomplex80: - { - ComplexExp *ce = (ComplexExp *)e; - return mixHash(CTFloat::hash(ce->toReal()), CTFloat::hash(ce->toImaginary())); - } - - case TOKidentifier: - return (size_t)(void *) ((IdentifierExp *)e)->ident; - - case TOKnull: - return (size_t)(void *) ((NullExp *)e)->type; - - case TOKstring: - { - StringExp *se = (StringExp *)e; - return calcHash((const char *)se->string, se->len * se->sz); - } - - case TOKtuple: - { - TupleExp *te = (TupleExp *)e; - size_t hash = 0; - hash += te->e0 ? expressionHash(te->e0) : 0; - for (size_t i = 0; i < te->exps->length; i++) - { - Expression *elem = (*te->exps)[i]; - hash = mixHash(hash, expressionHash(elem)); - } - return hash; - } - - case TOKarrayliteral: - { - ArrayLiteralExp *ae = (ArrayLiteralExp *)e; - size_t hash = 0; - for (size_t i = 0; i < ae->elements->length; i++) - hash = mixHash(hash, expressionHash(ae->getElement(i))); - return hash; - } - - case TOKassocarrayliteral: - { - AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e; - size_t hash = 0; - for (size_t i = 0; i < ae->keys->length; i++) - // reduction needs associative op as keys are unsorted (use XOR) - hash ^= mixHash(expressionHash((*ae->keys)[i]), expressionHash((*ae->values)[i])); - return hash; - } - - case TOKstructliteral: - { - StructLiteralExp *se = (StructLiteralExp *)e; - size_t hash = 0; - for (size_t i = 0; i < se->elements->length; i++) - { - Expression *elem = (*se->elements)[i]; - hash = mixHash(hash, elem ? expressionHash(elem) : 0); - } - return hash; - } - - case TOKvar: - return (size_t)(void *) ((VarExp *)e)->var; - - case TOKfunction: - return (size_t)(void *) ((FuncExp *)e)->fd; - - default: - // no custom equals for this expression - // equals based on identity - return (size_t)(void *) e; - } -} - - -/************************************ - * Return hash of Objects. - */ -static hash_t arrayObjectHash(Objects *oa1) -{ - hash_t hash = 0; - for (size_t j = 0; j < oa1->length; j++) - { - /* Must follow the logic of match() - */ - RootObject *o1 = (*oa1)[j]; - if (Type *t1 = isType(o1)) - hash = mixHash(hash, (size_t)t1->deco); - else if (Expression *e1 = getExpression(o1)) - hash = mixHash(hash, expressionHash(e1)); - else if (Dsymbol *s1 = isDsymbol(o1)) - { - FuncAliasDeclaration *fa1 = s1->isFuncAliasDeclaration(); - if (fa1) - s1 = fa1->toAliasFunc(); - hash = mixHash(hash, mixHash((size_t)(void *)s1->getIdent(), (size_t)(void *)s1->parent)); - } - else if (Tuple *u1 = isTuple(o1)) - hash = mixHash(hash, arrayObjectHash(&u1->objects)); - } - return hash; -} - -RootObject *objectSyntaxCopy(RootObject *o) -{ - if (!o) - return NULL; - if (Type *t = isType(o)) - return t->syntaxCopy(); - if (Expression *e = isExpression(o)) - return e->syntaxCopy(); - return o; -} - - -/* ======================== TemplateDeclaration ============================= */ - -TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, - TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, bool ismixin, bool literal) - : ScopeDsymbol(id) -{ - this->loc = loc; - this->parameters = parameters; - this->origParameters = parameters; - this->constraint = constraint; - this->members = decldefs; - this->overnext = NULL; - this->overroot = NULL; - this->funcroot = NULL; - this->onemember = NULL; - this->literal = literal; - this->ismixin = ismixin; - this->isstatic = true; - this->isTrivialAliasSeq = false; - this->isTrivialAlias = false; - this->previous = NULL; - this->protection = Prot(Prot::undefined); - this->inuse = 0; - this->instances = NULL; - - // Compute in advance for Ddoc's use - // Bugzilla 11153: ident could be NULL if parsing fails. - if (!members || !ident) - return; - - Dsymbol *s; - if (!Dsymbol::oneMembers(members, &s, ident) || !s) - return; - - onemember = s; - s->parent = this; - - /* Set isTrivialAliasSeq if this fits the pattern: - * template AliasSeq(T...) { alias AliasSeq = T; } - * or set isTrivialAlias if this fits the pattern: - * template Alias(T) { alias Alias = qualifiers(T); } - */ - if (!(parameters && parameters->length == 1)) - return; - - AliasDeclaration *ad = s->isAliasDeclaration(); - if (!ad || !ad->type) - return; - - TypeIdentifier *ti = ad->type->isTypeIdentifier(); - if (!ti || ti->idents.length != 0) - return; - - if (TemplateTupleParameter *ttp = (*parameters)[0]->isTemplateTupleParameter()) - { - if (ti->ident == ttp->ident && ti->mod == 0) - { - //printf("found isAliasSeq %s %s\n", s->toChars(), ad->type->toChars()); - isTrivialAliasSeq = true; - } - } - else if (TemplateTypeParameter *ttp = (*parameters)[0]->isTemplateTypeParameter()) - { - if (ti->ident == ttp->ident) - { - //printf("found isAlias %s %s\n", s->toChars(), ad->type->toChars()); - isTrivialAlias = true; - } - } -} - -Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) -{ - //printf("TemplateDeclaration::syntaxCopy()\n"); - TemplateParameters *p = NULL; - if (parameters) - { - p = new TemplateParameters(); - p->setDim(parameters->length); - for (size_t i = 0; i < p->length; i++) - (*p)[i] = (*parameters)[i]->syntaxCopy(); - } - return new TemplateDeclaration(loc, ident, p, - constraint ? constraint->syntaxCopy() : NULL, - Dsymbol::arraySyntaxCopy(members), ismixin, literal); -} - -const char *TemplateDeclaration::kind() const -{ - return (onemember && onemember->isAggregateDeclaration()) - ? onemember->kind() - : "template"; -} - -/********************************** - * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return true if successful; i.e. no conflict. - */ - -bool TemplateDeclaration::overloadInsert(Dsymbol *s) -{ - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { - if (funcroot) - return funcroot->overloadInsert(fd); - funcroot = fd; - return funcroot->overloadInsert(this); - } - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (!td) - return false; - - TemplateDeclaration *pthis = this; - TemplateDeclaration **ptd; - for (ptd = &pthis; *ptd; ptd = &(*ptd)->overnext) - { - } - - td->overroot = this; - *ptd = td; - return true; -} - -/**************************** - * Check to see if constraint is satisfied. - */ -bool TemplateDeclaration::evaluateConstraint( - TemplateInstance *ti, Scope *sc, Scope *paramscope, - Objects *dedargs, FuncDeclaration *fd) -{ - /* Detect recursive attempts to instantiate this template declaration, - * Bugzilla 4072 - * void foo(T)(T x) if (is(typeof(foo(x)))) { } - * static assert(!is(typeof(foo(7)))); - * Recursive attempts are regarded as a constraint failure. - */ - /* There's a chicken-and-egg problem here. We don't know yet if this template - * instantiation will be a local one (enclosing is set), and we won't know until - * after selecting the correct template. Thus, function we're nesting inside - * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). - * Workaround the problem by setting a flag to relax the checking on frame errors. - */ - - for (TemplatePrevious *p = previous; p; p = p->prev) - { - if (arrayObjectMatch(p->dedargs, dedargs)) - { - //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); - /* It must be a subscope of p->sc, other scope chains are not recursive - * instantiations. - */ - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (scx == p->sc) - return false; - } - } - /* BUG: should also check for ref param differences - */ - } - - TemplatePrevious pr; - pr.prev = previous; - pr.sc = paramscope; - pr.dedargs = dedargs; - previous = ≺ // add this to threaded list - - Scope *scx = paramscope->push(ti); - scx->parent = ti; - scx->tinst = NULL; - scx->minst = NULL; - - assert(!ti->symtab); - if (fd) - { - /* Declare all the function parameters as variables and add them to the scope - * Making parameters is similar to FuncDeclaration::semantic3 - */ - TypeFunction *tf = (TypeFunction *)fd->type; - assert(tf->ty == Tfunction); - - scx->parent = fd; - - Parameters *fparameters = tf->parameterList.parameters; - VarArg fvarargs = tf->parameterList.varargs; - - size_t nfparams = Parameter::dim(fparameters); - for (size_t i = 0; i < nfparams; i++) - { - Parameter *fparam = Parameter::getNth(fparameters, i); - fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); - fparam->storageClass |= STCparameter; - if (fvarargs == VARARGtypesafe && i + 1 == nfparams) - fparam->storageClass |= STCvariadic; - } - for (size_t i = 0; i < fparameters->length; i++) - { - Parameter *fparam = (*fparameters)[i]; - if (!fparam->ident) - continue; // don't add it, if it has no name - VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL); - v->storage_class = fparam->storageClass; - dsymbolSemantic(v, scx); - if (!ti->symtab) - ti->symtab = new DsymbolTable(); - if (!scx->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - else - v->parent = fd; - } - if (isstatic) - fd->storage_class |= STCstatic; - - fd->vthis = fd->declareThis(scx, fd->isThis()); - } - - Expression *e = constraint->syntaxCopy(); - - assert(ti->inst == NULL); - ti->inst = ti; // temporary instantiation to enable genIdent() - - scx->flags |= SCOPEconstraint; - bool errors = false; - bool result = evalStaticCondition(scx, constraint, e, errors); - ti->inst = NULL; - ti->symtab = NULL; - scx = scx->pop(); - previous = pr.prev; // unlink from threaded list - if (errors) - return false; - return result; -} - -/*************************************** - * Given that ti is an instance of this TemplateDeclaration, - * deduce the types of the parameters to this, and store - * those deduced types in dedtypes[]. - * Input: - * flag 1: don't do semantic() because of dummy types - * 2: don't change types in matchArg() - * Output: - * dedtypes deduced arguments - * Return match level. - */ - -MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti, - Objects *dedtypes, Expressions *fargs, int flag) -{ - MATCH m; - size_t dedtypes_dim = dedtypes->length; - - dedtypes->zero(); - - if (errors) - return MATCHnomatch; - - size_t parameters_dim = parameters->length; - int variadic = isVariadic() != NULL; - - // If more arguments than parameters, no match - if (ti->tiargs->length > parameters_dim && !variadic) - { - return MATCHnomatch; - } - - assert(dedtypes_dim == parameters_dim); - assert(dedtypes_dim >= ti->tiargs->length || variadic); - - assert(_scope); - - // Set up scope for template parameters - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = _scope->parent; - Scope *paramscope = _scope->push(paramsym); - paramscope->tinst = ti; - paramscope->minst = sc->minst; - paramscope->callsc = sc; - paramscope->stc = 0; - - // Attempt type deduction - m = MATCHexact; - for (size_t i = 0; i < dedtypes_dim; i++) - { - MATCH m2; - TemplateParameter *tp = (*parameters)[i]; - Declaration *sparam; - - //printf("\targument [%d]\n", i); - inuse++; - m2 = tp->matchArg(ti->loc, paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); - inuse--; - //printf("\tm2 = %d\n", m2); - - if (m2 == MATCHnomatch) - { - goto Lnomatch; - } - - if (m2 < m) - m = m2; - - if (!flag) - dsymbolSemantic(sparam, paramscope); - if (!paramscope->insert(sparam)) // TODO: This check can make more early - goto Lnomatch; // in TemplateDeclaration::semantic, and - // then we don't need to make sparam if flags == 0 - } - - if (!flag) - { - /* Any parameter left without a type gets the type of - * its corresponding arg - */ - for (size_t i = 0; i < dedtypes_dim; i++) - { - if (!(*dedtypes)[i]) - { - assert(i < ti->tiargs->length); - (*dedtypes)[i] = (Type *)(*ti->tiargs)[i]; - } - } - } - - if (m > MATCHnomatch && constraint && !flag) - { - if (ti->hasNestedArgs(ti->tiargs, this->isstatic)) // TODO: should gag error - ti->parent = ti->enclosing; - else - ti->parent = this->parent; - - // Similar to doHeaderInstantiation - FuncDeclaration *fd = onemember ? onemember->isFuncDeclaration() : NULL; - if (fd) - { - assert(fd->type->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy(); - - fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, tf); - fd->parent = ti; - fd->inferRetType = true; - - // Shouldn't run semantic on default arguments and return type. - for (size_t i = 0; i < tf->parameterList.parameters->length; i++) - (*tf->parameterList.parameters)[i]->defaultArg = NULL; - tf->next = NULL; - - // Resolve parameter types and 'auto ref's. - tf->fargs = fargs; - unsigned olderrors = global.startGagging(); - fd->type = typeSemantic(tf, loc, paramscope); - if (global.endGagging(olderrors)) - { - assert(fd->type->ty != Tfunction); - goto Lnomatch; - } - assert(fd->type->ty == Tfunction); - fd->originalType = fd->type; // for mangling - } - - // TODO: dedtypes => ti->tiargs ? - if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd)) - goto Lnomatch; - } - - goto Lret; - -Lnomatch: - m = MATCHnomatch; - -Lret: - paramscope->pop(); - return m; -} - -/******************************************** - * Determine partial specialization order of 'this' vs td2. - * Returns: - * match this is at least as specialized as td2 - * 0 td2 is more specialized than this - */ - -MATCH TemplateDeclaration::leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs) -{ - /* This works by taking the template parameters to this template - * declaration and feeding them to td2 as if it were a template - * instance. - * If it works, then this template is at least as specialized - * as td2. - */ - - TemplateInstance ti(Loc(), ident); // create dummy template instance - // Set type arguments to dummy template instance to be types - // generated from the parameters to this template declaration - ti.tiargs = new Objects(); - ti.tiargs->reserve(parameters->length); - for (size_t i = 0; i < parameters->length; i++) - { - TemplateParameter *tp = (*parameters)[i]; - if (tp->dependent) - break; - RootObject *p = (RootObject *)tp->dummyArg(); - if (!p) - break; - - ti.tiargs->push(p); - } - - // Temporary Array to hold deduced types - Objects dedtypes; - dedtypes.setDim(td2->parameters->length); - - // Attempt a type deduction - MATCH m = td2->matchWithInstance(sc, &ti, &dedtypes, fargs, 1); - if (m > MATCHnomatch) - { - /* A non-variadic template is more specialized than a - * variadic one. - */ - TemplateTupleParameter *tp = isVariadic(); - if (tp && !tp->dependent && !td2->isVariadic()) - goto L1; - - return m; - } - L1: - return MATCHnomatch; -} - -static Expression *emptyArrayElement = NULL; - -class TypeDeduced : public Type -{ -public: - Type *tded; - Expressions argexps; // corresponding expressions - Types tparams; // tparams[i]->mod - - TypeDeduced(Type *tt, Expression *e, Type *tparam) - : Type(Tnone) - { - tded = tt; - argexps.push(e); - tparams.push(tparam); - } - - virtual ~TypeDeduced() - { - } - - void update(Expression *e, Type *tparam) - { - argexps.push(e); - tparams.push(tparam); - } - void update(Type *tt, Expression *e, Type *tparam) - { - tded = tt; - argexps.push(e); - tparams.push(tparam); - } - MATCH matchAll(Type *tt) - { - MATCH match = MATCHexact; - for (size_t j = 0; j < argexps.length; j++) - { - Expression *e = argexps[j]; - assert(e); - if (e == emptyArrayElement) - continue; - - Type *t = tt->addMod(tparams[j]->mod)->substWildTo(MODconst); - - MATCH m = e->implicitConvTo(t); - if (match > m) - match = m; - if (match <= MATCHnomatch) - break; - } - return match; - } -}; - -/************************************************* - * Match function arguments against a specific template function. - * Input: - * ti - * sc instantiation scope - * fd - * tthis 'this' argument if !NULL - * fargs arguments to function - * Output: - * fd Partially instantiated function declaration - * ti->tdtypes Expression/Type deduced template arguments - * Returns: - * match level - * bit 0-3 Match template parameters by inferred template arguments - * bit 4-7 Match template parameters by initial template arguments - */ - -MATCH TemplateDeclaration::deduceFunctionTemplateMatch( - TemplateInstance *ti, Scope *sc, - FuncDeclaration *&fd, Type *tthis, Expressions *fargs) -{ - size_t nfparams; - size_t nfargs; - size_t ntargs; // array size of tiargs - size_t fptupindex = IDX_NOTFOUND; - MATCH match = MATCHexact; - MATCH matchTiargs = MATCHexact; - ParameterList fparameters; // function parameter list - unsigned wildmatch = 0; - size_t inferStart = 0; - - Loc instLoc = ti->loc; - Objects *tiargs = ti->tiargs; - Objects *dedargs = new Objects(); - Objects* dedtypes = &ti->tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T - - assert(_scope); - - dedargs->setDim(parameters->length); - dedargs->zero(); - - dedtypes->setDim(parameters->length); - dedtypes->zero(); - - if (errors || fd->errors) - return MATCHnomatch; - - // Set up scope for parameters - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = _scope->parent; // should use hasnestedArgs and enclosing? - Scope *paramscope = _scope->push(paramsym); - paramscope->tinst = ti; - paramscope->minst = sc->minst; - paramscope->callsc = sc; - paramscope->stc = 0; - - TemplateTupleParameter *tp = isVariadic(); - Tuple *declaredTuple = NULL; - - ntargs = 0; - if (tiargs) - { - // Set initial template arguments - ntargs = tiargs->length; - size_t n = parameters->length; - if (tp) - n--; - if (ntargs > n) - { - if (!tp) - goto Lnomatch; - - /* The extra initial template arguments - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - assert(parameters->length); - (*dedargs)[parameters->length - 1] = t; - - t->objects.setDim(ntargs - n); - for (size_t i = 0; i < t->objects.length; i++) - { - t->objects[i] = (*tiargs)[n + i]; - } - declareParameter(paramscope, tp, t); - declaredTuple = t; - } - else - n = ntargs; - - memcpy(dedargs->tdata(), tiargs->tdata(), n * sizeof(*dedargs->tdata())); - - for (size_t i = 0; i < n; i++) - { - assert(i < parameters->length); - Declaration *sparam = NULL; - MATCH m = (*parameters)[i]->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam); - //printf("\tdeduceType m = %d\n", m); - if (m <= MATCHnomatch) - goto Lnomatch; - if (m < matchTiargs) - matchTiargs = m; - - dsymbolSemantic(sparam, paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; - } - if (n < parameters->length && !declaredTuple) - { - inferStart = n; - } - else - inferStart = parameters->length; - //printf("tiargs matchTiargs = %d\n", matchTiargs); - } - - fparameters = fd->getParameterList(); - nfparams = fparameters.length(); // number of function parameters - nfargs = fargs ? fargs->length : 0; // number of function arguments - - /* Check for match of function arguments with variadic template - * parameter, such as: - * - * void foo(T, A...)(T t, A a); - * void main() { foo(1,2,3); } - */ - if (tp) // if variadic - { - // TemplateTupleParameter always makes most lesser matching. - matchTiargs = MATCHconvert; - - if (nfparams == 0 && nfargs != 0) // if no function parameters - { - if (!declaredTuple) - { - Tuple *t = new Tuple(); - //printf("t = %p\n", t); - (*dedargs)[parameters->length - 1] = t; - declareParameter(paramscope, tp, t); - declaredTuple = t; - } - } - else - { - /* Figure out which of the function parameters matches - * the tuple template parameter. Do this by matching - * type identifiers. - * Set the index of this function parameter to fptupindex. - */ - for (fptupindex = 0; fptupindex < nfparams; fptupindex++) - { - Parameter *fparam = (*fparameters.parameters)[fptupindex]; - if (fparam->type->ty != Tident) - continue; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (!tp->ident->equals(tid->ident) || tid->idents.length) - continue; - - if (fparameters.varargs != VARARGnone) // variadic function doesn't - goto Lnomatch; // go with variadic template - - goto L1; - } - fptupindex = IDX_NOTFOUND; - L1: - ; - } - } - - if (toParent()->isModule() || (_scope->stc & STCstatic)) - tthis = NULL; - if (tthis) - { - bool hasttp = false; - - // Match 'tthis' to any TemplateThisParameter's - for (size_t i = 0; i < parameters->length; i++) - { - TemplateThisParameter *ttp = (*parameters)[i]->isTemplateThisParameter(); - if (ttp) - { - hasttp = true; - - Type *t = new TypeIdentifier(Loc(), ttp->ident); - MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes); - if (m <= MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; // pick worst match - } - } - - // Match attributes of tthis against attributes of fd - if (fd->type && !fd->isCtorDeclaration()) - { - StorageClass stc = _scope->stc | fd->storage_class2; - // Propagate parent storage class (see bug 5504) - Dsymbol *p = parent; - while (p->isTemplateDeclaration() || p->isTemplateInstance()) - p = p->parent; - AggregateDeclaration *ad = p->isAggregateDeclaration(); - if (ad) - stc |= ad->storage_class; - - unsigned char mod = fd->type->mod; - if (stc & STCimmutable) - mod = MODimmutable; - else - { - if (stc & (STCshared | STCsynchronized)) - mod |= MODshared; - if (stc & STCconst) - mod |= MODconst; - if (stc & STCwild) - mod |= MODwild; - } - - unsigned char thismod = tthis->mod; - if (hasttp) - mod = MODmerge(thismod, mod); - MATCH m = MODmethodConv(thismod, mod); - if (m <= MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - } - } - - // Loop through the function parameters - { - //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple->objects.length : 0); - //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple->toChars() : NULL); - size_t argi = 0; - size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs - for (size_t parami = 0; parami < nfparams; parami++) - { - Parameter *fparam = fparameters[parami]; - - // Apply function parameter storage classes to parameter types - Type *prmtype = fparam->type->addStorageClass(fparam->storageClass); - - Expression *farg; - - /* See function parameters which wound up - * as part of a template tuple parameter. - */ - if (fptupindex != IDX_NOTFOUND && parami == fptupindex) - { - assert(prmtype->ty == Tident); - TypeIdentifier *tid = (TypeIdentifier *)prmtype; - if (!declaredTuple) - { - /* The types of the function arguments - * now form the tuple argument. - */ - declaredTuple = new Tuple(); - (*dedargs)[parameters->length - 1] = declaredTuple; - - /* Count function parameters following a tuple parameter. - * void foo(U, T...)(int y, T, U, int) {} // rem == 2 (U, int) - */ - size_t rem = 0; - for (size_t j = parami + 1; j < nfparams; j++) - { - Parameter *p = fparameters[j]; - if (!reliesOnTident(p->type, parameters, inferStart)) - { - Type *pt = typeSemantic(p->type->syntaxCopy(), fd->loc, paramscope); - rem += pt->ty == Ttuple ? ((TypeTuple *)pt)->arguments->length : 1; - } - else - { - ++rem; - } - } - - if (nfargs2 - argi < rem) - goto Lnomatch; - declaredTuple->objects.setDim(nfargs2 - argi - rem); - for (size_t i = 0; i < declaredTuple->objects.length; i++) - { - farg = (*fargs)[argi + i]; - - // Check invalid arguments to detect errors early. - if (farg->op == TOKerror || farg->type->ty == Terror) - goto Lnomatch; - - if (!(fparam->storageClass & STClazy) && farg->type->ty == Tvoid) - goto Lnomatch; - - Type *tt; - MATCH m; - if (unsigned char wm = deduceWildHelper(farg->type, &tt, tid)) - { - wildmatch |= wm; - m = MATCHconst; - } - else - { - m = deduceTypeHelper(farg->type, &tt, tid); - } - if (m <= MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - - /* Remove top const for dynamic array types and pointer types - */ - if ((tt->ty == Tarray || tt->ty == Tpointer) && - !tt->isMutable() && - (!(fparam->storageClass & STCref) || - ((fparam->storageClass & STCauto) && !farg->isLvalue()))) - { - tt = tt->mutableOf(); - } - declaredTuple->objects[i] = tt; - } - declareParameter(paramscope, tp, declaredTuple); - } - else - { - // Bugzilla 6810: If declared tuple is not a type tuple, - // it cannot be function parameter types. - for (size_t i = 0; i < declaredTuple->objects.length; i++) - { - if (!isType(declaredTuple->objects[i])) - goto Lnomatch; - } - } - assert(declaredTuple); - argi += declaredTuple->objects.length; - continue; - } - - // If parameter type doesn't depend on inferred template parameters, - // semantic it to get actual type. - if (!reliesOnTident(prmtype, parameters, inferStart)) - { - // should copy prmtype to avoid affecting semantic result - prmtype = typeSemantic(prmtype->syntaxCopy(), fd->loc, paramscope); - - if (prmtype->ty == Ttuple) - { - TypeTuple *tt = (TypeTuple *)prmtype; - size_t tt_dim = tt->arguments->length; - for (size_t j = 0; j < tt_dim; j++, ++argi) - { - Parameter *p = (*tt->arguments)[j]; - if (j == tt_dim - 1 && fparameters.varargs == VARARGtypesafe && - parami + 1 == nfparams && argi < nfargs) - { - prmtype = p->type; - goto Lvarargs; - } - if (argi >= nfargs) - { - if (p->defaultArg) - continue; - goto Lnomatch; - } - farg = (*fargs)[argi]; - if (!farg->implicitConvTo(p->type)) - goto Lnomatch; - } - continue; - } - } - - if (argi >= nfargs) // if not enough arguments - { - if (!fparam->defaultArg) - goto Lvarargs; - - /* Bugzilla 2803: Before the starting of type deduction from the function - * default arguments, set the already deduced parameters into paramscope. - * It's necessary to avoid breaking existing acceptable code. Cases: - * - * 1. Already deduced template parameters can appear in fparam->defaultArg: - * auto foo(A, B)(A a, B b = A.stringof); - * foo(1); - * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int' - * - * 2. If prmtype depends on default-specified template parameter, the - * default type should be preferred. - * auto foo(N = size_t, R)(R r, N start = 0) - * foo([1,2,3]); - * // at fparam `N start = 0`, N should be 'size_t' before - * // the deduction result from fparam->defaultArg. - */ - if (argi == nfargs) - { - for (size_t i = 0; i < dedtypes->length; i++) - { - Type *at = isType((*dedtypes)[i]); - if (at && at->ty == Tnone) - { - TypeDeduced *xt = (TypeDeduced *)at; - (*dedtypes)[i] = xt->tded; // 'unbox' - delete xt; - } - } - for (size_t i = ntargs; i < dedargs->length; i++) - { - TemplateParameter *tparam = (*parameters)[i]; - - RootObject *oarg = (*dedargs)[i]; - RootObject *oded = (*dedtypes)[i]; - if (!oarg) - { - if (oded) - { - if (tparam->specialization() || !tparam->isTemplateTypeParameter()) - { - /* The specialization can work as long as afterwards - * the oded == oarg - */ - (*dedargs)[i] = oded; - MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL); - //printf("m2 = %d\n", m2); - if (m2 <= MATCHnomatch) - goto Lnomatch; - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i]->equals(oded)) - error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); - } - else - { - if (MATCHconvert < matchTiargs) - matchTiargs = MATCHconvert; - } - (*dedargs)[i] = declareParameter(paramscope, tparam, oded); - } - else - { - inuse++; - oded = tparam->defaultArg(instLoc, paramscope); - inuse--; - if (oded) - (*dedargs)[i] = declareParameter(paramscope, tparam, oded); - } - } - } - } - nfargs2 = argi + 1; - - /* If prmtype does not depend on any template parameters: - * - * auto foo(T)(T v, double x = 0); - * foo("str"); - * // at fparam == 'double x = 0' - * - * or, if all template parameters in the prmtype are already deduced: - * - * auto foo(R)(R range, ElementType!R sum = 0); - * foo([1,2,3]); - * // at fparam == 'ElementType!R sum = 0' - * - * Deducing prmtype from fparam->defaultArg is not necessary. - */ - if (prmtype->deco || - prmtype->syntaxCopy()->trySemantic(loc, paramscope)) - { - ++argi; - continue; - } - - // Deduce prmtype from the defaultArg. - farg = fparam->defaultArg->syntaxCopy(); - farg = expressionSemantic(farg, paramscope); - farg = resolveProperties(paramscope, farg); - } - else - { - farg = (*fargs)[argi]; - } - { - // Check invalid arguments to detect errors early. - if (farg->op == TOKerror || farg->type->ty == Terror) - goto Lnomatch; - - Type *att = NULL; - Lretry: - Type *argtype = farg->type; - - if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid && farg->op != TOKfunction) - goto Lnomatch; - - // Bugzilla 12876: optimize arugument to allow CT-known length matching - farg = farg->optimize(WANTvalue, (fparam->storageClass & (STCref | STCout)) != 0); - //printf("farg = %s %s\n", farg->type->toChars(), farg->toChars()); - - RootObject *oarg = farg; - if ((fparam->storageClass & STCref) && - (!(fparam->storageClass & STCauto) || farg->isLvalue())) - { - /* Allow expressions that have CT-known boundaries and type [] to match with [dim] - */ - Type *taai; - if (argtype->ty == Tarray && - (prmtype->ty == Tsarray || - (prmtype->ty == Taarray && (taai = ((TypeAArray *)prmtype)->index)->ty == Tident && - ((TypeIdentifier *)taai)->idents.length == 0))) - { - if (farg->op == TOKstring) - { - StringExp *se = (StringExp *)farg; - argtype = se->type->nextOf()->sarrayOf(se->len); - } - else if (farg->op == TOKarrayliteral) - { - ArrayLiteralExp *ae = (ArrayLiteralExp *)farg; - argtype = ae->type->nextOf()->sarrayOf(ae->elements->length); - } - else if (farg->op == TOKslice) - { - SliceExp *se = (SliceExp *)farg; - if (Type *tsa = toStaticArrayType(se)) - argtype = tsa; - } - } - - oarg = argtype; - } - else if ((fparam->storageClass & STCout) == 0 && - (argtype->ty == Tarray || argtype->ty == Tpointer) && - templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && - ((TypeIdentifier *)prmtype)->idents.length == 0) - { - /* The farg passing to the prmtype always make a copy. Therefore, - * we can shrink the set of the deduced type arguments for prmtype - * by adjusting top-qualifier of the argtype. - * - * prmtype argtype ta - * T <- const(E)[] const(E)[] - * T <- const(E[]) const(E)[] - * qualifier(T) <- const(E)[] const(E[]) - * qualifier(T) <- const(E[]) const(E[]) - */ - Type *ta = argtype->castMod(prmtype->mod ? argtype->nextOf()->mod : 0); - if (ta != argtype) - { - Expression *ea = farg->copy(); - ea->type = ta; - oarg = ea; - } - } - - if (fparameters.varargs == VARARGtypesafe && parami + 1 == nfparams && argi + 1 < nfargs) - goto Lvarargs; - - unsigned wm = 0; - MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &wm, inferStart); - //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch); - wildmatch |= wm; - - /* If no match, see if the argument can be matched by using - * implicit conversions. - */ - if (m == MATCHnomatch && prmtype->deco) - m = farg->implicitConvTo(prmtype); - - if (m == MATCHnomatch) - { - AggregateDeclaration *ad = isAggregate(farg->type); - if (ad && ad->aliasthis && argtype != att) - { - if (!att && argtype->checkAliasThisRec()) // Bugzilla 12537 - att = argtype; - - /* If a semantic error occurs while doing alias this, - * eg purity(bug 7295), just regard it as not a match. - */ - if (Expression *e = resolveAliasThis(sc, farg, true)) - { - farg = e; - goto Lretry; - } - } - } - - if (m > MATCHnomatch && (fparam->storageClass & (STCref | STCauto)) == STCref) - { - if (!farg->isLvalue()) - { - if ((farg->op == TOKstring || farg->op == TOKslice) && - (prmtype->ty == Tsarray || prmtype->ty == Taarray)) - { - // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] - } - else - goto Lnomatch; - } - } - if (m > MATCHnomatch && (fparam->storageClass & STCout)) - { - if (!farg->isLvalue()) - goto Lnomatch; - if (!farg->type->isMutable()) // Bugzilla 11916 - goto Lnomatch; - } - if (m == MATCHnomatch && (fparam->storageClass & STClazy) && prmtype->ty == Tvoid && - farg->type->ty != Tvoid) - m = MATCHconvert; - - if (m != MATCHnomatch) - { - if (m < match) - match = m; // pick worst match - argi++; - continue; - } - } - - Lvarargs: - /* The following code for variadic arguments closely - * matches TypeFunction::callMatch() - */ - if (!(fparameters.varargs == VARARGtypesafe && parami + 1 == nfparams)) - goto Lnomatch; - - /* Check for match with function parameter T... - */ - Type *tb = prmtype->toBasetype(); - switch (tb->ty) - { - // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic(). - case Tsarray: - case Taarray: - // Perhaps we can do better with this, see TypeFunction::callMatch() - if (tb->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)tb; - dinteger_t sz = tsa->dim->toInteger(); - if (sz != nfargs - argi) - goto Lnomatch; - } - else if (tb->ty == Taarray) - { - TypeAArray *taa = (TypeAArray *)tb; - Expression *dim = new IntegerExp(instLoc, nfargs - argi, Type::tsize_t); - - size_t i = templateParameterLookup(taa->index, parameters); - if (i == IDX_NOTFOUND) - { - Expression *e; - Type *t; - Dsymbol *s; - Scope *sco; - - unsigned errors = global.startGagging(); - /* ref: https://issues.dlang.org/show_bug.cgi?id=11118 - * The parameter isn't part of the template - * ones, let's try to find it in the - * instantiation scope 'sc' and the one - * belonging to the template itself. */ - sco = sc; - taa->index->resolve(instLoc, sco, &e, &t, &s); - if (!e) - { - sco = paramscope; - taa->index->resolve(instLoc, sco, &e, &t, &s); - } - global.endGagging(errors); - - if (!e) - { - goto Lnomatch; - } - - e = e->ctfeInterpret(); - e = e->implicitCastTo(sco, Type::tsize_t); - e = e->optimize(WANTvalue); - if (!dim->equals(e)) - goto Lnomatch; - } - else - { - // This code matches code in TypeInstance::deduceType() - TemplateParameter *tprm = (*parameters)[i]; - TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); - if (!tvp) - goto Lnomatch; - Expression *e = (Expression *)(*dedtypes)[i]; - if (e) - { - if (!dim->equals(e)) - goto Lnomatch; - } - else - { - Type *vt = typeSemantic(tvp->valType, Loc(), sc); - MATCH m = (MATCH)dim->implicitConvTo(vt); - if (m <= MATCHnomatch) - goto Lnomatch; - (*dedtypes)[i] = dim; - } - } - } - /* fall through */ - case Tarray: - { - TypeArray *ta = (TypeArray *)tb; - Type *tret = fparam->isLazyArray(); - for (; argi < nfargs; argi++) - { - Expression *arg = (*fargs)[argi]; - assert(arg); - - MATCH m; - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - if (tret) - { - if (ta->next->equals(arg->type)) - { - m = MATCHexact; - } - else - { - m = arg->implicitConvTo(tret); - if (m == MATCHnomatch) - { - if (tret->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - } - } - else - { - unsigned wm = 0; - m = deduceType(arg, paramscope, ta->next, parameters, dedtypes, &wm, inferStart); - wildmatch |= wm; - } - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - } - goto Lmatch; - } - case Tclass: - case Tident: - goto Lmatch; - - default: - goto Lnomatch; - } - ++argi; - } - //printf("-> argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2); - if (argi != nfargs2 && fparameters.varargs == VARARGnone) - goto Lnomatch; - } - -Lmatch: - - for (size_t i = 0; i < dedtypes->length; i++) - { - Type *at = isType((*dedtypes)[i]); - if (at) - { - if (at->ty == Tnone) - { - TypeDeduced *xt = (TypeDeduced *)at; - at = xt->tded; // 'unbox' - delete xt; - } - (*dedtypes)[i] = at->merge2(); - } - } - for (size_t i = ntargs; i < dedargs->length; i++) - { - TemplateParameter *tparam = (*parameters)[i]; - //printf("tparam[%d] = %s\n", i, tparam->ident->toChars()); - /* For T:T*, the dedargs is the T*, dedtypes is the T - * But for function templates, we really need them to match - */ - RootObject *oarg = (*dedargs)[i]; - RootObject *oded = (*dedtypes)[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); - //if (oarg) printf("oarg: %s\n", oarg->toChars()); - //if (oded) printf("oded: %s\n", oded->toChars()); - if (!oarg) - { - if (oded) - { - if (tparam->specialization() || !tparam->isTemplateTypeParameter()) - { - /* The specialization can work as long as afterwards - * the oded == oarg - */ - (*dedargs)[i] = oded; - MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL); - //printf("m2 = %d\n", m2); - if (m2 <= MATCHnomatch) - goto Lnomatch; - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i]->equals(oded)) - error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); - } - else - { - if (MATCHconvert < matchTiargs) - matchTiargs = MATCHconvert; - } - } - else - { - inuse++; - oded = tparam->defaultArg(instLoc, paramscope); - inuse--; - if (!oded) - { - // if tuple parameter and - // tuple parameter was not in function parameter list and - // we're one or more arguments short (i.e. no tuple argument) - if (tparam == tp && - fptupindex == IDX_NOTFOUND && - ntargs <= dedargs->length - 1) - { - // make tuple argument an empty tuple - oded = (RootObject *)new Tuple(); - } - else - goto Lnomatch; - } - if (isError(oded)) - goto Lerror; - ntargs++; - - /* At the template parameter T, the picked default template argument - * X!int should be matched to T in order to deduce dependent - * template parameter A. - * auto foo(T : X!A = X!int, A...)() { ... } - * foo(); // T <-- X!int, A <-- (int) - */ - if (tparam->specialization()) - { - (*dedargs)[i] = oded; - MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL); - //printf("m2 = %d\n", m2); - if (m2 <= MATCHnomatch) - goto Lnomatch; - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i]->equals(oded)) - error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); - } - } - oded = declareParameter(paramscope, tparam, oded); - (*dedargs)[i] = oded; - } - } - - /* Bugzilla 7469: As same as the code for 7469 in findBestMatch, - * expand a Tuple in dedargs to normalize template arguments. - */ - if (size_t d = dedargs->length) - { - if (Tuple *va = isTuple((*dedargs)[d - 1])) - { - if (va->objects.length) - { - dedargs->setDim(d - 1); - dedargs->insert(d - 1, &va->objects); - } - } - } - ti->tiargs = dedargs; // update to the normalized template arguments. - - // Partially instantiate function for constraint and fd->leastAsSpecialized() - { - assert(paramsym); - Scope *sc2 = _scope; - sc2 = sc2->push(paramsym); - sc2 = sc2->push(ti); - sc2->parent = ti; - sc2->tinst = ti; - sc2->minst = sc->minst; - - fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs); - - sc2 = sc2->pop(); - sc2 = sc2->pop(); - - if (!fd) - goto Lnomatch; - } - - if (constraint) - { - if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd)) - goto Lnomatch; - } - - paramscope->pop(); - //printf("\tmatch %d\n", match); - return (MATCH)(match | (matchTiargs<<4)); - -Lnomatch: - paramscope->pop(); - //printf("\tnomatch\n"); - return MATCHnomatch; - -Lerror: // todo: for the future improvement - paramscope->pop(); - //printf("\terror\n"); - return MATCHnomatch; -} - -/************************************************** - * Declare template parameter tp with value o, and install it in the scope sc. - */ - -RootObject *TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o) -{ - //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o); - - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - - Declaration *d; - VarDeclaration *v = NULL; - - if (ea && ea->op == TOKtype) - ta = ea->type; - else if (ea && ea->op == TOKscope) - sa = ((ScopeExp *)ea)->sds; - else if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) - sa = ((ThisExp *)ea)->var; - else if (ea && ea->op == TOKfunction) - { - if (((FuncExp *)ea)->td) - sa = ((FuncExp *)ea)->td; - else - sa = ((FuncExp *)ea)->fd; - } - - if (ta) - { - //printf("type %s\n", ta->toChars()); - d = new AliasDeclaration(Loc(), tp->ident, ta); - } - else if (sa) - { - //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); - d = new AliasDeclaration(Loc(), tp->ident, sa); - } - else if (ea) - { - // tdtypes.data[i] always matches ea here - Initializer *init = new ExpInitializer(loc, ea); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - - Type *t = tvp ? tvp->valType : NULL; - - v = new VarDeclaration(loc, t, tp->ident, init); - v->storage_class = STCmanifest | STCtemplateparameter; - d = v; - } - else if (va) - { - //printf("\ttuple\n"); - d = new TupleDeclaration(loc, tp->ident, &va->objects); - } - else - { - assert(0); - } - - d->storage_class |= STCtemplateparameter; - if (ta) - { - Type *t = ta; - // consistent with Type::checkDeprecated() - while (t->ty != Tenum) - { - if (!t->nextOf()) break; - t = ((TypeNext *)t)->next; - } - if (Dsymbol *s = t->toDsymbol(sc)) - { - if (s->isDeprecated()) - d->storage_class |= STCdeprecated; - } - } - else if (sa) - { - if (sa->isDeprecated()) - d->storage_class |= STCdeprecated; - } - - if (!sc->insert(d)) - error("declaration %s is already defined", tp->ident->toChars()); - dsymbolSemantic(d, sc); - - /* So the caller's o gets updated with the result of semantic() being run on o - */ - if (v) - o = initializerToExpression(v->_init); - return o; -} - -/************************************** - * Determine if TemplateDeclaration is variadic. - */ - -TemplateTupleParameter *isVariadic(TemplateParameters *parameters) -{ - size_t dim = parameters->length; - TemplateTupleParameter *tp = NULL; - - if (dim) - tp = ((*parameters)[dim - 1])->isTemplateTupleParameter(); - return tp; -} - -TemplateTupleParameter *TemplateDeclaration::isVariadic() -{ - return ::isVariadic(parameters); -} - -/*********************************** - * We can overload templates. - */ - -bool TemplateDeclaration::isOverloadable() -{ - return true; -} - -/************************************************* - * Given function arguments, figure out which template function - * to expand, and return matching result. - * Params: - * m = matching result - * dstart = the root of overloaded function templates - * loc = instantiation location - * sc = instantiation scope - * tiargs = initial list of template arguments - * tthis = if !NULL, the 'this' pointer argument - * fargs = arguments to function - * pMessage = address to store error message, or null - */ - -void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, - Objects *tiargs, Type *tthis, Expressions *fargs, const char **pMessage) -{ - struct ParamDeduce - { - // context - Loc loc; - Scope *sc; - Type *tthis; - Objects *tiargs; - Expressions *fargs; - const char **pMessage; - // result - Match *m; - int property; // 0: unintialized - // 1: seen @property - // 2: not @property - size_t ov_index; - TemplateDeclaration *td_best; - TemplateInstance *ti_best; - MATCH ta_last; - Type *tthis_best; - - static int fp(void *param, Dsymbol *s) - { - if (s->errors) - return 0; - if (FuncDeclaration *fd = s->isFuncDeclaration()) - return ((ParamDeduce *)param)->applyFunction(fd); - if (TemplateDeclaration *td = s->isTemplateDeclaration()) - return ((ParamDeduce *)param)->applyTemplate(td); - return 0; - } - - int applyFunction(FuncDeclaration *fd) - { - // skip duplicates - if (fd == m->lastf) - return 0; - // explicitly specified tiargs never match to non template function - if (tiargs && tiargs->length > 0) - return 0; - - // constructors need a valid scope in order to detect semantic errors - if (!fd->isCtorDeclaration() && - fd->semanticRun < PASSsemanticdone) - { - Ungag ungag = fd->ungagSpeculative(); - dsymbolSemantic(fd, NULL); - } - if (fd->semanticRun < PASSsemanticdone) - { - ::error(loc, "forward reference to template %s", fd->toChars()); - return 1; - } - //printf("fd = %s %s, fargs = %s\n", fd->toChars(), fd->type->toChars(), fargs->toChars()); - m->anyf = fd; - TypeFunction *tf = (TypeFunction *)fd->type; - - int prop = (tf->isproperty) ? 1 : 2; - if (property == 0) - property = prop; - else if (property != prop) - error(fd->loc, "cannot overload both property and non-property functions"); - - /* For constructors, qualifier check will be opposite direction. - * Qualified constructor always makes qualified object, then will be checked - * that it is implicitly convertible to tthis. - */ - Type *tthis_fd = fd->needThis() ? tthis : NULL; - bool isCtorCall = tthis_fd && fd->isCtorDeclaration(); - if (isCtorCall) - { - //printf("%s tf->mod = x%x tthis_fd->mod = x%x %d\n", tf->toChars(), - // tf->mod, tthis_fd->mod, fd->isolateReturn()); - if (MODimplicitConv(tf->mod, tthis_fd->mod) || - (tf->isWild() && tf->isShared() == tthis_fd->isShared()) || - fd->isolateReturn()) - { - /* && tf->isShared() == tthis_fd->isShared()*/ - // Uniquely constructed object can ignore shared qualifier. - // TODO: Is this appropriate? - tthis_fd = NULL; - } - else - return 0; // MATCHnomatch - } - MATCH mfa = tf->callMatch(tthis_fd, fargs, 0, pMessage); - //printf("test1: mfa = %d\n", mfa); - if (mfa > MATCHnomatch) - { - if (mfa > m->last) goto LfIsBetter; - if (mfa < m->last) goto LlastIsBetter; - - /* See if one of the matches overrides the other. - */ - assert(m->lastf); - if (m->lastf->overrides(fd)) goto LlastIsBetter; - if (fd->overrides(m->lastf)) goto LfIsBetter; - - /* Try to disambiguate using template-style partial ordering rules. - * In essence, if f() and g() are ambiguous, if f() can call g(), - * but g() cannot call f(), then pick f(). - * This is because f() is "more specialized." - */ - { - MATCH c1 = fd->leastAsSpecialized(m->lastf); - MATCH c2 = m->lastf->leastAsSpecialized(fd); - //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto LfIsBetter; - if (c1 < c2) goto LlastIsBetter; - } - - /* The 'overrides' check above does covariant checking only - * for virtual member functions. It should do it for all functions, - * but in order to not risk breaking code we put it after - * the 'leastAsSpecialized' check. - * In the future try moving it before. - * I.e. a not-the-same-but-covariant match is preferred, - * as it is more restrictive. - */ - if (!m->lastf->type->equals(fd->type)) - { - //printf("cov: %d %d\n", m->lastf->type->covariant(fd->type), fd->type->covariant(m->lastf->type)); - if (m->lastf->type->covariant(fd->type) == 1) goto LlastIsBetter; - if (fd->type->covariant(m->lastf->type) == 1) goto LfIsBetter; - } - - /* If the two functions are the same function, like: - * int foo(int); - * int foo(int x) { ... } - * then pick the one with the body. - */ - if (tf->equals(m->lastf->type) && - fd->storage_class == m->lastf->storage_class && - fd->parent == m->lastf->parent && - fd->protection == m->lastf->protection && - fd->linkage == m->lastf->linkage) - { - if ( fd->fbody && !m->lastf->fbody) goto LfIsBetter; - if (!fd->fbody && m->lastf->fbody) goto LlastIsBetter; - } - - // Bugzilla 14450: Prefer exact qualified constructor for the creating object type - if (isCtorCall && tf->mod != m->lastf->type->mod) - { - if (tthis->mod == tf->mod) goto LfIsBetter; - if (tthis->mod == m->lastf->type->mod) goto LlastIsBetter; - } - - m->nextf = fd; - m->count++; - return 0; - - LlastIsBetter: - return 0; - - LfIsBetter: - td_best = NULL; - ti_best = NULL; - ta_last = MATCHexact; - m->last = mfa; - m->lastf = fd; - tthis_best = tthis_fd; - ov_index = 0; - m->count = 1; - return 0; - } - return 0; - } - - int applyTemplate(TemplateDeclaration *td) - { - //printf("applyTemplate()\n"); - if (td->inuse) - { - td->error(loc, "recursive template expansion"); - return 1; - } - if (td == td_best) // skip duplicates - return 0; - - if (!sc) - sc = td->_scope; // workaround for Type::aliasthisOf - - if (td->semanticRun == PASSinit && td->_scope) - { - // Try to fix forward reference. Ungag errors while doing so. - Ungag ungag = td->ungagSpeculative(); - dsymbolSemantic(td, td->_scope); - } - if (td->semanticRun == PASSinit) - { - ::error(loc, "forward reference to template %s", td->toChars()); - Lerror: - m->lastf = NULL; - m->count = 0; - m->last = MATCHnomatch; - return 1; - } - //printf("td = %s\n", td->toChars()); - - FuncDeclaration *f; - f = td->onemember ? td->onemember->isFuncDeclaration() : NULL; - if (!f) - { - if (!tiargs) - tiargs = new Objects(); - TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); - Objects dedtypes; - dedtypes.setDim(td->parameters->length); - assert(td->semanticRun != PASSinit); - MATCH mta = td->matchWithInstance(sc, ti, &dedtypes, fargs, 0); - //printf("matchWithInstance = %d\n", mta); - if (mta <= MATCHnomatch || mta < ta_last) // no match or less match - return 0; - - templateInstanceSemantic(ti, sc, fargs); - if (!ti->inst) // if template failed to expand - return 0; - - Dsymbol *s = ti->inst->toAlias(); - FuncDeclaration *fd; - if (TemplateDeclaration *tdx = s->isTemplateDeclaration()) - { - Objects dedtypesX; // empty tiargs - - // Bugzilla 11553: Check for recursive instantiation of tdx. - for (TemplatePrevious *p = tdx->previous; p; p = p->prev) - { - if (arrayObjectMatch(p->dedargs, &dedtypesX)) - { - //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); - /* It must be a subscope of p->sc, other scope chains are not recursive - * instantiations. - */ - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (scx == p->sc) - { - error(loc, "recursive template expansion while looking for %s.%s", ti->toChars(), tdx->toChars()); - goto Lerror; - } - } - } - /* BUG: should also check for ref param differences - */ - } - - TemplatePrevious pr; - pr.prev = tdx->previous; - pr.sc = sc; - pr.dedargs = &dedtypesX; - tdx->previous = ≺ // add this to threaded list - - fd = resolveFuncCall(loc, sc, s, NULL, tthis, fargs, 1); - - tdx->previous = pr.prev; // unlink from threaded list - } - else if (s->isFuncDeclaration()) - { - fd = resolveFuncCall(loc, sc, s, NULL, tthis, fargs, 1); - } - else - goto Lerror; - - if (!fd) - return 0; - - if (fd->type->ty != Tfunction) - { - m->lastf = fd; // to propagate "error match" - m->count = 1; - m->last = MATCHnomatch; - return 1; - } - - Type *tthis_fd = fd->needThis() && !fd->isCtorDeclaration() ? tthis : NULL; - - TypeFunction *tf = (TypeFunction *)fd->type; - MATCH mfa = tf->callMatch(tthis_fd, fargs); - if (mfa < m->last) - return 0; - - if (mta < ta_last) goto Ltd_best2; - if (mta > ta_last) goto Ltd2; - - if (mfa < m->last) goto Ltd_best2; - if (mfa > m->last) goto Ltd2; - - //printf("Lambig2\n"); - m->nextf = fd; - m->count++; - return 0; - - Ltd_best2: - return 0; - - Ltd2: - // td is the new best match - assert(td->_scope); - td_best = td; - ti_best = NULL; - property = 0; // (backward compatibility) - ta_last = mta; - m->last = mfa; - m->lastf = fd; - tthis_best = tthis_fd; - ov_index = 0; - m->nextf = NULL; - m->count = 1; - return 0; - } - - //printf("td = %s\n", td->toChars()); - for (size_t ovi = 0; f; f = f->overnext0, ovi++) - { - if (f->type->ty != Tfunction || f->errors) - goto Lerror; - - /* This is a 'dummy' instance to evaluate constraint properly. - */ - TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); - ti->parent = td->parent; // Maybe calculating valid 'enclosing' is unnecessary. - - FuncDeclaration *fd = f; - int x = td->deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs); - MATCH mta = (MATCH)(x >> 4); - MATCH mfa = (MATCH)(x & 0xF); - //printf("match:t/f = %d/%d\n", mta, mfa); - if (!fd || mfa == MATCHnomatch) - continue; - - Type *tthis_fd = fd->needThis() ? tthis : NULL; - - bool isCtorCall = tthis_fd && fd->isCtorDeclaration(); - if (isCtorCall) - { - // Constructor call requires additional check. - - TypeFunction *tf = (TypeFunction *)fd->type; - assert(tf->next); - if (MODimplicitConv(tf->mod, tthis_fd->mod) || - (tf->isWild() && tf->isShared() == tthis_fd->isShared()) || - fd->isolateReturn()) - { - tthis_fd = NULL; - } - else - continue; // MATCHnomatch - } - - if (mta < ta_last) goto Ltd_best; - if (mta > ta_last) goto Ltd; - - if (mfa < m->last) goto Ltd_best; - if (mfa > m->last) goto Ltd; - - if (td_best) - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(sc, td_best, fargs); - MATCH c2 = td_best->leastAsSpecialized(sc, td, fargs); - //printf("1: c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto Ltd; - if (c1 < c2) goto Ltd_best; - } - assert(fd && m->lastf); - { - // Disambiguate by tf->callMatch - TypeFunction *tf1 = (TypeFunction *)fd->type; - assert(tf1->ty == Tfunction); - TypeFunction *tf2 = (TypeFunction *)m->lastf->type; - assert(tf2->ty == Tfunction); - MATCH c1 = tf1->callMatch(tthis_fd, fargs); - MATCH c2 = tf2->callMatch(tthis_best, fargs); - //printf("2: c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto Ltd; - if (c1 < c2) goto Ltd_best; - } - { - // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = fd->leastAsSpecialized(m->lastf); - MATCH c2 = m->lastf->leastAsSpecialized(fd); - //printf("3: c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto Ltd; - if (c1 < c2) goto Ltd_best; - } - - // Bugzilla 14450: Prefer exact qualified constructor for the creating object type - if (isCtorCall && fd->type->mod != m->lastf->type->mod) - { - if (tthis->mod == fd->type->mod) goto Ltd; - if (tthis->mod == m->lastf->type->mod) goto Ltd_best; - } - - m->nextf = fd; - m->count++; - continue; - - Ltd_best: // td_best is the best match so far - //printf("Ltd_best\n"); - continue; - - Ltd: // td is the new best match - //printf("Ltd\n"); - assert(td->_scope); - td_best = td; - ti_best = ti; - property = 0; // (backward compatibility) - ta_last = mta; - m->last = mfa; - m->lastf = fd; - tthis_best = tthis_fd; - ov_index = ovi; - m->nextf = NULL; - m->count = 1; - continue; - } - return 0; - } - }; - ParamDeduce p; - // context - p.loc = loc; - p.sc = sc; - p.tthis = tthis; - p.tiargs = tiargs; - p.fargs = fargs; - p.pMessage = pMessage; - - // result - p.m = m; - p.property = 0; - p.ov_index = 0; - p.td_best = NULL; - p.ti_best = NULL; - p.ta_last = m->last != MATCHnomatch ? MATCHexact : MATCHnomatch; - p.tthis_best = NULL; - - TemplateDeclaration *td = dstart->isTemplateDeclaration(); - if (td && td->funcroot) - dstart = td->funcroot; - - overloadApply(dstart, &p, &ParamDeduce::fp); - - //printf("td_best = %p, m->lastf = %p\n", p.td_best, m->lastf); - if (p.td_best && p.ti_best && m->count == 1) - { - // Matches to template function - assert(p.td_best->onemember && p.td_best->onemember->isFuncDeclaration()); - - /* The best match is td_best with arguments tdargs. - * Now instantiate the template. - */ - assert(p.td_best->_scope); - if (!sc) - sc = p.td_best->_scope; // workaround for Type::aliasthisOf - - TemplateInstance *ti = new TemplateInstance(loc, p.td_best, p.ti_best->tiargs); - templateInstanceSemantic(ti, sc, fargs); - - m->lastf = ti->toAlias()->isFuncDeclaration(); - if (!m->lastf) - goto Lnomatch; - if (ti->errors) - { - Lerror: - m->count = 1; - assert(m->lastf); - m->last = MATCHnomatch; - return; - } - - // look forward instantiated overload function - // Dsymbol::oneMembers is alredy called in TemplateInstance::semantic. - // it has filled overnext0d - while (p.ov_index--) - { - m->lastf = m->lastf->overnext0; - assert(m->lastf); - } - - p.tthis_best = m->lastf->needThis() && !m->lastf->isCtorDeclaration() ? tthis : NULL; - - TypeFunction *tf = (TypeFunction *)m->lastf->type; - if (tf->ty == Terror) - goto Lerror; - assert(tf->ty == Tfunction); - if (!tf->callMatch(p.tthis_best, fargs)) - goto Lnomatch; - - /* As Bugzilla 3682 shows, a template instance can be matched while instantiating - * that same template. Thus, the function type can be incomplete. Complete it. - * - * Bugzilla 9208: For auto function, completion should be deferred to the end of - * its semantic3. Should not complete it in here. - */ - if (tf->next && !m->lastf->inferRetType) - { - m->lastf->type = typeSemantic(tf, loc, sc); - } - } - else if (m->lastf) - { - // Matches to non template function, - // or found matches were ambiguous. - assert(m->count >= 1); - } - else - { - Lnomatch: - m->count = 0; - m->lastf = NULL; - m->last = MATCHnomatch; - } -} - -/************************************************* - * Limited function template instantiation for using fd->leastAsSpecialized() - */ -FuncDeclaration *TemplateDeclaration::doHeaderInstantiation( - TemplateInstance *ti, Scope *sc2, - FuncDeclaration *fd, Type *tthis, Expressions *fargs) -{ - assert(fd); - - // function body and contracts are not need - if (fd->isCtorDeclaration()) - fd = new CtorDeclaration(fd->loc, fd->endloc, fd->storage_class, fd->type->syntaxCopy()); - else - fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy()); - fd->parent = ti; - - assert(fd->type->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)fd->type; - tf->fargs = fargs; - - if (tthis) - { - // Match 'tthis' to any TemplateThisParameter's - bool hasttp = false; - for (size_t i = 0; i < parameters->length; i++) - { - TemplateParameter *tp = (*parameters)[i]; - TemplateThisParameter *ttp = tp->isTemplateThisParameter(); - if (ttp) - hasttp = true; - } - if (hasttp) - { - tf = (TypeFunction *)tf->addSTC(ModToStc(tthis->mod)); - assert(!tf->deco); - } - } - - Scope *scx = sc2->push(); - - // Shouldn't run semantic on default arguments and return type. - for (size_t i = 0; i < tf->parameterList.parameters->length; i++) - (*tf->parameterList.parameters)[i]->defaultArg = NULL; - if (fd->isCtorDeclaration()) - { - // For constructors, emitting return type is necessary for - // isolateReturn() in functionResolve. - scx->flags |= SCOPEctor; - - Dsymbol *parent = toParent2(); - Type *tret; - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (!ad || parent->isUnionDeclaration()) - { - tret = Type::tvoid; - } - else - { - tret = ad->handleType(); - assert(tret); - tret = tret->addStorageClass(fd->storage_class | scx->stc); - tret = tret->addMod(tf->mod); - } - tf->next = tret; - if (ad && ad->isStructDeclaration()) - tf->isref = 1; - //printf("tf = %s\n", tf->toChars()); - } - else - tf->next = NULL; - fd->type = tf; - fd->type = fd->type->addSTC(scx->stc); - fd->type = typeSemantic(fd->type, fd->loc, scx); - scx = scx->pop(); - - if (fd->type->ty != Tfunction) - return NULL; - - fd->originalType = fd->type; // for mangling - //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod); - //printf("fd->needThis() = %d\n", fd->needThis()); - - return fd; -} - -bool TemplateDeclaration::hasStaticCtorOrDtor() -{ - return false; // don't scan uninstantiated templates -} - -const char *TemplateDeclaration::toChars() -{ - if (literal) - return Dsymbol::toChars(); - - OutBuffer buf; - HdrGenState hgs; - - buf.writestring(ident->toChars()); - buf.writeByte('('); - for (size_t i = 0; i < parameters->length; i++) - { - TemplateParameter *tp = (*parameters)[i]; - if (i) - buf.writestring(", "); - ::toCBuffer(tp, &buf, &hgs); - } - buf.writeByte(')'); - - if (onemember) - { - FuncDeclaration *fd = onemember->isFuncDeclaration(); - if (fd && fd->type) - { - TypeFunction *tf = (TypeFunction *)fd->type; - buf.writestring(parametersTypeToChars(tf->parameterList)); - } - } - - if (constraint) - { - buf.writestring(" if ("); - ::toCBuffer(constraint, &buf, &hgs); - buf.writeByte(')'); - } - return buf.extractChars(); -} - -Prot TemplateDeclaration::prot() -{ - return protection; -} - -/**************************************************** - * Given a new instance tithis of this TemplateDeclaration, - * see if there already exists an instance. - * If so, return that existing instance. - */ - -TemplateInstance *TemplateDeclaration::findExistingInstance(TemplateInstance *tithis, Expressions *fargs) -{ - //printf("findExistingInstance(%p)\n", tithis); - tithis->fargs = fargs; - TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)instances, (void *)tithis->toHash()); - if (tinstances) - { - for (size_t i = 0; i < tinstances->length; i++) - { - TemplateInstance *ti = (*tinstances)[i]; - if (tithis->compare(ti) == 0) - return ti; - } - } - return NULL; -} - -/******************************************** - * Add instance ti to TemplateDeclaration's table of instances. - * Return a handle we can use to later remove it if it fails instantiation. - */ - -TemplateInstance *TemplateDeclaration::addInstance(TemplateInstance *ti) -{ - //printf("addInstance() %p %p\n", instances, ti); - TemplateInstances **ptinstances = (TemplateInstances **)dmd_aaGet((AA **)&instances, (void *)ti->toHash()); - if (!*ptinstances) - *ptinstances = new TemplateInstances(); - (*ptinstances)->push(ti); - return ti; -} - -/******************************************* - * Remove TemplateInstance from table of instances. - * Input: - * handle returned by addInstance() - */ - -void TemplateDeclaration::removeInstance(TemplateInstance *handle) -{ - //printf("removeInstance()\n"); - TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)instances, (void *)handle->toHash()); - if (tinstances) - { - for (size_t i = 0; i < tinstances->length; i++) - { - TemplateInstance *ti = (*tinstances)[i]; - if (handle == ti) - { - tinstances->remove(i); - break; - } - } - } -} - -/* ======================== Type ============================================ */ - -/**** - * Given an identifier, figure out which TemplateParameter it is. - * Return IDX_NOTFOUND if not found. - */ - -static size_t templateIdentifierLookup(Identifier *id, TemplateParameters *parameters) -{ - for (size_t i = 0; i < parameters->length; i++) - { - TemplateParameter *tp = (*parameters)[i]; - if (tp->ident->equals(id)) - return i; - } - return IDX_NOTFOUND; -} - -size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters) -{ - if (tparam->ty == Tident) - { - TypeIdentifier *tident = (TypeIdentifier *)tparam; - //printf("\ttident = '%s'\n", tident->toChars()); - return templateIdentifierLookup(tident->ident, parameters); - } - return IDX_NOTFOUND; -} - -unsigned char deduceWildHelper(Type *t, Type **at, Type *tparam) -{ - if ((tparam->mod & MODwild) == 0) - return 0; - - *at = NULL; - - #define X(U,T) ((U) << 4) | (T) - switch (X(tparam->mod, t->mod)) - { - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODshared): - case X(MODwild, MODshared | MODconst): - case X(MODwild, MODimmutable): - case X(MODwildconst, 0): - case X(MODwildconst, MODconst): - case X(MODwildconst, MODshared): - case X(MODwildconst, MODshared | MODconst): - case X(MODwildconst, MODimmutable): - case X(MODshared | MODwild, MODshared): - case X(MODshared | MODwild, MODshared | MODconst): - case X(MODshared | MODwild, MODimmutable): - case X(MODshared | MODwildconst, MODshared): - case X(MODshared | MODwildconst, MODshared | MODconst): - case X(MODshared | MODwildconst, MODimmutable): - { - unsigned char wm = (t->mod & ~MODshared); - if (wm == 0) - wm = MODmutable; - unsigned char m = (t->mod & (MODconst | MODimmutable)) | (tparam->mod & t->mod & MODshared); - *at = t->unqualify(m); - return wm; - } - - case X(MODwild, MODwild): - case X(MODwild, MODwildconst): - case X(MODwild, MODshared | MODwild): - case X(MODwild, MODshared | MODwildconst): - case X(MODwildconst, MODwild): - case X(MODwildconst, MODwildconst): - case X(MODwildconst, MODshared | MODwild): - case X(MODwildconst, MODshared | MODwildconst): - case X(MODshared | MODwild, MODshared | MODwild): - case X(MODshared | MODwild, MODshared | MODwildconst): - case X(MODshared | MODwildconst, MODshared | MODwild): - case X(MODshared | MODwildconst, MODshared | MODwildconst): - { - *at = t->unqualify(tparam->mod & t->mod); - return MODwild; - } - - default: - return 0; - } - #undef X -} - -MATCH deduceTypeHelper(Type *t, Type **at, Type *tparam) -{ - // 9*9 == 81 cases - - #define X(U,T) ((U) << 4) | (T) - switch (X(tparam->mod, t->mod)) - { - case X(0, 0): - case X(0, MODconst): - case X(0, MODwild): - case X(0, MODwildconst): - case X(0, MODshared): - case X(0, MODshared | MODconst): - case X(0, MODshared | MODwild): - case X(0, MODshared | MODwildconst): - case X(0, MODimmutable): - // foo(U) T => T - // foo(U) const(T) => const(T) - // foo(U) inout(T) => inout(T) - // foo(U) inout(const(T)) => inout(const(T)) - // foo(U) shared(T) => shared(T) - // foo(U) shared(const(T)) => shared(const(T)) - // foo(U) shared(inout(T)) => shared(inout(T)) - // foo(U) shared(inout(const(T))) => shared(inout(const(T))) - // foo(U) immutable(T) => immutable(T) - { - *at = t; - return MATCHexact; - } - - case X(MODconst, MODconst): - case X(MODwild, MODwild): - case X(MODwildconst, MODwildconst): - case X(MODshared, MODshared): - case X(MODshared | MODconst, MODshared | MODconst): - case X(MODshared | MODwild, MODshared | MODwild): - case X(MODshared | MODwildconst, MODshared | MODwildconst): - case X(MODimmutable, MODimmutable): - // foo(const(U)) const(T) => T - // foo(inout(U)) inout(T) => T - // foo(inout(const(U))) inout(const(T)) => T - // foo(shared(U)) shared(T) => T - // foo(shared(const(U))) shared(const(T)) => T - // foo(shared(inout(U))) shared(inout(T)) => T - // foo(shared(inout(const(U)))) shared(inout(const(T))) => T - // foo(immutable(U)) immutable(T) => T - { - *at = t->mutableOf()->unSharedOf(); - return MATCHexact; - } - - case X(MODconst, 0): - case X(MODconst, MODwild): - case X(MODconst, MODwildconst): - case X(MODconst, MODshared | MODconst): - case X(MODconst, MODshared | MODwild): - case X(MODconst, MODshared | MODwildconst): - case X(MODconst, MODimmutable): - case X(MODwild, MODshared | MODwild): - case X(MODwildconst, MODshared | MODwildconst): - case X(MODshared | MODconst, MODimmutable): - // foo(const(U)) T => T - // foo(const(U)) inout(T) => T - // foo(const(U)) inout(const(T)) => T - // foo(const(U)) shared(const(T)) => shared(T) - // foo(const(U)) shared(inout(T)) => shared(T) - // foo(const(U)) shared(inout(const(T))) => shared(T) - // foo(const(U)) immutable(T) => T - // foo(inout(U)) shared(inout(T)) => shared(T) - // foo(inout(const(U))) shared(inout(const(T))) => shared(T) - // foo(shared(const(U))) immutable(T) => T - { - *at = t->mutableOf(); - return MATCHconst; - } - - case X(MODconst, MODshared): - // foo(const(U)) shared(T) => shared(T) - { - *at = t; - return MATCHconst; - } - - case X(MODshared, MODshared | MODconst): - case X(MODshared, MODshared | MODwild): - case X(MODshared, MODshared | MODwildconst): - case X(MODshared | MODconst, MODshared): - // foo(shared(U)) shared(const(T)) => const(T) - // foo(shared(U)) shared(inout(T)) => inout(T) - // foo(shared(U)) shared(inout(const(T))) => inout(const(T)) - // foo(shared(const(U))) shared(T) => T - { - *at = t->unSharedOf(); - return MATCHconst; - } - - case X(MODwildconst, MODimmutable): - case X(MODshared | MODconst, MODshared | MODwildconst): - case X(MODshared | MODwildconst, MODimmutable): - case X(MODshared | MODwildconst, MODshared | MODwild): - // foo(inout(const(U))) immutable(T) => T - // foo(shared(const(U))) shared(inout(const(T))) => T - // foo(shared(inout(const(U)))) immutable(T) => T - // foo(shared(inout(const(U)))) shared(inout(T)) => T - { - *at = t->unSharedOf()->mutableOf(); - return MATCHconst; - } - - case X(MODshared | MODconst, MODshared | MODwild): - // foo(shared(const(U))) shared(inout(T)) => T - { - *at = t->unSharedOf()->mutableOf(); - return MATCHconst; - } - - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODwildconst): - case X(MODwild, MODimmutable): - case X(MODwild, MODshared): - case X(MODwild, MODshared | MODconst): - case X(MODwild, MODshared | MODwildconst): - case X(MODwildconst, 0): - case X(MODwildconst, MODconst): - case X(MODwildconst, MODwild): - case X(MODwildconst, MODshared): - case X(MODwildconst, MODshared | MODconst): - case X(MODwildconst, MODshared | MODwild): - case X(MODshared, 0): - case X(MODshared, MODconst): - case X(MODshared, MODwild): - case X(MODshared, MODwildconst): - case X(MODshared, MODimmutable): - case X(MODshared | MODconst, 0): - case X(MODshared | MODconst, MODconst): - case X(MODshared | MODconst, MODwild): - case X(MODshared | MODconst, MODwildconst): - case X(MODshared | MODwild, 0): - case X(MODshared | MODwild, MODconst): - case X(MODshared | MODwild, MODwild): - case X(MODshared | MODwild, MODwildconst): - case X(MODshared | MODwild, MODimmutable): - case X(MODshared | MODwild, MODshared): - case X(MODshared | MODwild, MODshared | MODconst): - case X(MODshared | MODwild, MODshared | MODwildconst): - case X(MODshared | MODwildconst, 0): - case X(MODshared | MODwildconst, MODconst): - case X(MODshared | MODwildconst, MODwild): - case X(MODshared | MODwildconst, MODwildconst): - case X(MODshared | MODwildconst, MODshared): - case X(MODshared | MODwildconst, MODshared | MODconst): - case X(MODimmutable, 0): - case X(MODimmutable, MODconst): - case X(MODimmutable, MODwild): - case X(MODimmutable, MODwildconst): - case X(MODimmutable, MODshared): - case X(MODimmutable, MODshared | MODconst): - case X(MODimmutable, MODshared | MODwild): - case X(MODimmutable, MODshared | MODwildconst): - // foo(inout(U)) T => nomatch - // foo(inout(U)) const(T) => nomatch - // foo(inout(U)) inout(const(T)) => nomatch - // foo(inout(U)) immutable(T) => nomatch - // foo(inout(U)) shared(T) => nomatch - // foo(inout(U)) shared(const(T)) => nomatch - // foo(inout(U)) shared(inout(const(T))) => nomatch - // foo(inout(const(U))) T => nomatch - // foo(inout(const(U))) const(T) => nomatch - // foo(inout(const(U))) inout(T) => nomatch - // foo(inout(const(U))) shared(T) => nomatch - // foo(inout(const(U))) shared(const(T)) => nomatch - // foo(inout(const(U))) shared(inout(T)) => nomatch - // foo(shared(U)) T => nomatch - // foo(shared(U)) const(T) => nomatch - // foo(shared(U)) inout(T) => nomatch - // foo(shared(U)) inout(const(T)) => nomatch - // foo(shared(U)) immutable(T) => nomatch - // foo(shared(const(U))) T => nomatch - // foo(shared(const(U))) const(T) => nomatch - // foo(shared(const(U))) inout(T) => nomatch - // foo(shared(const(U))) inout(const(T)) => nomatch - // foo(shared(inout(U))) T => nomatch - // foo(shared(inout(U))) const(T) => nomatch - // foo(shared(inout(U))) inout(T) => nomatch - // foo(shared(inout(U))) inout(const(T)) => nomatch - // foo(shared(inout(U))) immutable(T) => nomatch - // foo(shared(inout(U))) shared(T) => nomatch - // foo(shared(inout(U))) shared(const(T)) => nomatch - // foo(shared(inout(U))) shared(inout(const(T))) => nomatch - // foo(shared(inout(const(U)))) T => nomatch - // foo(shared(inout(const(U)))) const(T) => nomatch - // foo(shared(inout(const(U)))) inout(T) => nomatch - // foo(shared(inout(const(U)))) inout(const(T)) => nomatch - // foo(shared(inout(const(U)))) shared(T) => nomatch - // foo(shared(inout(const(U)))) shared(const(T)) => nomatch - // foo(immutable(U)) T => nomatch - // foo(immutable(U)) const(T) => nomatch - // foo(immutable(U)) inout(T) => nomatch - // foo(immutable(U)) inout(const(T)) => nomatch - // foo(immutable(U)) shared(T) => nomatch - // foo(immutable(U)) shared(const(T)) => nomatch - // foo(immutable(U)) shared(inout(T)) => nomatch - // foo(immutable(U)) shared(inout(const(T))) => nomatch - return MATCHnomatch; - - default: - assert(0); - return MATCHnomatch; // silence compiler warning about missing return - } - #undef X -} - -/* These form the heart of template argument deduction. - * Given 'this' being the type argument to the template instance, - * it is matched against the template declaration parameter specialization - * 'tparam' to determine the type to be used for the parameter. - * Example: - * template Foo(T:T*) // template declaration - * Foo!(int*) // template instantiation - * Input: - * this = int* - * tparam = T* - * parameters = [ T:T* ] // Array of TemplateParameter's - * Output: - * dedtypes = [ int ] // Array of Expression/Type's - */ -MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wm, size_t inferStart) -{ - class DeduceType : public Visitor - { - public: - Scope *sc; - Type *tparam; - TemplateParameters *parameters; - Objects *dedtypes; - unsigned *wm; - size_t inferStart; - MATCH result; - - DeduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm, size_t inferStart) - : sc(sc), tparam(tparam), parameters(parameters), dedtypes(dedtypes), wm(wm), inferStart(inferStart) - { - result = MATCHnomatch; - } - - void visit(Type *t) - { - if (!tparam) - goto Lnomatch; - - if (t == tparam) - goto Lexact; - - if (tparam->ty == Tident) - { - // Determine which parameter tparam is - size_t i = templateParameterLookup(tparam, parameters); - if (i == IDX_NOTFOUND) - { - if (!sc) - goto Lnomatch; - - /* Need a loc to go with the semantic routine. - */ - Loc loc; - if (parameters->length) - { - TemplateParameter *tp = (*parameters)[0]; - loc = tp->loc; - } - - /* BUG: what if tparam is a template instance, that - * has as an argument another Tident? - */ - tparam = typeSemantic(tparam, loc, sc); - assert(tparam->ty != Tident); - result = deduceType(t, sc, tparam, parameters, dedtypes, wm); - return; - } - - TemplateParameter *tp = (*parameters)[i]; - - TypeIdentifier *tident = (TypeIdentifier *)tparam; - if (tident->idents.length > 0) - { - //printf("matching %s to %s\n", tparam->toChars(), t->toChars()); - Dsymbol *s = t->toDsymbol(sc); - for (size_t j = tident->idents.length; j-- > 0; ) - { - RootObject *id = tident->idents[j]; - if (id->dyncast() == DYNCAST_IDENTIFIER) - { - if (!s || !s->parent) - goto Lnomatch; - Dsymbol *s2 = s->parent->search(Loc(), (Identifier *)id); - if (!s2) - goto Lnomatch; - s2 = s2->toAlias(); - //printf("[%d] s = %s %s, s2 = %s %s\n", j, s->kind(), s->toChars(), s2->kind(), s2->toChars()); - if (s != s2) - { - if (Type *tx = s2->getType()) - { - if (s != tx->toDsymbol(sc)) - goto Lnomatch; - } - else - goto Lnomatch; - } - s = s->parent; - } - else - goto Lnomatch; - } - //printf("[e] s = %s\n", s?s->toChars():"(null)"); - if (tp->isTemplateTypeParameter()) - { - Type *tt = s->getType(); - if (!tt) - goto Lnomatch; - Type *at = (Type *)(*dedtypes)[i]; - if (at && at->ty == Tnone) - at = ((TypeDeduced *)at)->tded; - if (!at || tt->equals(at)) - { - (*dedtypes)[i] = tt; - goto Lexact; - } - } - if (tp->isTemplateAliasParameter()) - { - Dsymbol *s2 = (Dsymbol *)(*dedtypes)[i]; - if (!s2 || s == s2) - { - (*dedtypes)[i] = s; - goto Lexact; - } - } - goto Lnomatch; - } - - // Found the corresponding parameter tp - if (!tp->isTemplateTypeParameter()) - goto Lnomatch; - - Type *at = (Type *)(*dedtypes)[i]; - Type *tt; - if (unsigned char wx = wm ? deduceWildHelper(t, &tt, tparam) : 0) - { - // type vs (none) - if (!at) - { - (*dedtypes)[i] = tt; - *wm |= wx; - result = MATCHconst; - return; - } - - // type vs expressions - if (at->ty == Tnone) - { - TypeDeduced *xt = (TypeDeduced *)at; - result = xt->matchAll(tt); - if (result > MATCHnomatch) - { - (*dedtypes)[i] = tt; - if (result > MATCHconst) - result = MATCHconst; // limit level for inout matches - delete xt; - } - return; - } - - // type vs type - if (tt->equals(at)) - { - (*dedtypes)[i] = tt; // Prefer current type match - goto Lconst; - } - if (tt->implicitConvTo(at->constOf())) - { - (*dedtypes)[i] = at->constOf()->mutableOf(); - *wm |= MODconst; - goto Lconst; - } - if (at->implicitConvTo(tt->constOf())) - { - (*dedtypes)[i] = tt->constOf()->mutableOf(); - *wm |= MODconst; - goto Lconst; - } - goto Lnomatch; - } - else if (MATCH m = deduceTypeHelper(t, &tt, tparam)) - { - // type vs (none) - if (!at) - { - (*dedtypes)[i] = tt; - result = m; - return; - } - - // type vs expressions - if (at->ty == Tnone) - { - TypeDeduced *xt = (TypeDeduced *)at; - result = xt->matchAll(tt); - if (result > MATCHnomatch) - { - (*dedtypes)[i] = tt; - delete xt; - } - return; - } - - // type vs type - if (tt->equals(at)) - { - goto Lexact; - } - if (tt->ty == Tclass && at->ty == Tclass) - { - result = tt->implicitConvTo(at); - return; - } - if (tt->ty == Tsarray && at->ty == Tarray && - tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst) - { - goto Lexact; - } - } - goto Lnomatch; - } - - if (tparam->ty == Ttypeof) - { - /* Need a loc to go with the semantic routine. - */ - Loc loc; - if (parameters->length) - { - TemplateParameter *tp = (*parameters)[0]; - loc = tp->loc; - } - - tparam = typeSemantic(tparam, loc, sc); - } - if (t->ty != tparam->ty) - { - if (Dsymbol *sym = t->toDsymbol(sc)) - { - if (sym->isforwardRef() && !tparam->deco) - goto Lnomatch; - } - - MATCH m = t->implicitConvTo(tparam); - if (m == MATCHnomatch) - { - if (t->ty == Tclass) - { - TypeClass *tc = (TypeClass *)t; - if (tc->sym->aliasthis && !(tc->att & RECtracingDT)) - { - tc->att = (AliasThisRec)(tc->att | RECtracingDT); - m = deduceType(t->aliasthisOf(), sc, tparam, parameters, dedtypes, wm); - tc->att = (AliasThisRec)(tc->att & ~RECtracingDT); - } - } - else if (t->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)t; - if (ts->sym->aliasthis && !(ts->att & RECtracingDT)) - { - ts->att = (AliasThisRec)(ts->att | RECtracingDT); - m = deduceType(t->aliasthisOf(), sc, tparam, parameters, dedtypes, wm); - ts->att = (AliasThisRec)(ts->att & ~RECtracingDT); - } - } - } - result = m; - return; - } - - if (t->nextOf()) - { - if (tparam->deco && !tparam->hasWild()) - { - result = t->implicitConvTo(tparam); - return; - } - - Type *tpn = tparam->nextOf(); - if (wm && t->ty == Taarray && tparam->isWild()) - { - // Bugzilla 12403: In IFTI, stop inout matching on transitive part of AA types. - tpn = tpn->substWildTo(MODmutable); - } - - result = deduceType(t->nextOf(), sc, tpn, parameters, dedtypes, wm); - return; - } - - Lexact: - result = MATCHexact; - return; - - Lnomatch: - result = MATCHnomatch; - return; - - Lconst: - result = MATCHconst; - } - - void visit(TypeVector *t) - { - if (tparam->ty == Tvector) - { - TypeVector *tp = (TypeVector *)tparam; - result = deduceType(t->basetype, sc, tp->basetype, parameters, dedtypes, wm); - return; - } - visit((Type *)t); - } - - void visit(TypeDArray *t) - { - visit((Type *)t); - } - - void visit(TypeSArray *t) - { - // Extra check that array dimensions must match - if (tparam) - { - if (tparam->ty == Tarray) - { - MATCH m = deduceType(t->next, sc, tparam->nextOf(), parameters, dedtypes, wm); - result = (m >= MATCHconst) ? MATCHconvert : MATCHnomatch; - return; - } - - TemplateParameter *tp = NULL; - Expression *edim = NULL; - size_t i; - if (tparam->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)tparam; - if (tsa->dim->op == TOKvar && - ((VarExp *)tsa->dim)->var->storage_class & STCtemplateparameter) - { - Identifier *id = ((VarExp *)tsa->dim)->var->ident; - i = templateIdentifierLookup(id, parameters); - assert(i != IDX_NOTFOUND); - tp = (*parameters)[i]; - } - else - edim = tsa->dim; - } - else if (tparam->ty == Taarray) - { - TypeAArray *taa = (TypeAArray *)tparam; - i = templateParameterLookup(taa->index, parameters); - if (i != IDX_NOTFOUND) - tp = (*parameters)[i]; - else - { - Expression *e; - Type *tx; - Dsymbol *s; - taa->index->resolve(Loc(), sc, &e, &tx, &s); - edim = s ? getValue(s) : getValue(e); - } - } - if ((tp && tp->matchArg(sc, t->dim, i, parameters, dedtypes, NULL)) || - (edim && edim->toInteger() == t->dim->toInteger())) - { - result = deduceType(t->next, sc, tparam->nextOf(), parameters, dedtypes, wm); - return; - } - } - visit((Type *)t); - return; - - result = MATCHnomatch; - } - - void visit(TypeAArray *t) - { - // Extra check that index type must match - if (tparam && tparam->ty == Taarray) - { - TypeAArray *tp = (TypeAArray *)tparam; - if (!deduceType(t->index, sc, tp->index, parameters, dedtypes)) - { - result = MATCHnomatch; - return; - } - } - visit((Type *)t); - } - - void visit(TypeFunction *t) - { - //printf("TypeFunction::deduceType()\n"); - //printf("\tthis = %d, ", t->ty); t->print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - // Extra check that function characteristics must match - if (tparam && tparam->ty == Tfunction) - { - TypeFunction *tp = (TypeFunction *)tparam; - if (t->parameterList.varargs != tp->parameterList.varargs || - t->linkage != tp->linkage) - { - result = MATCHnomatch; - return; - } - - size_t nfargs = t->parameterList.length(); - size_t nfparams = tp->parameterList.length(); - - // bug 2579 fix: Apply function parameter storage classes to parameter types - for (size_t i = 0; i < nfparams; i++) - { - Parameter *fparam = tp->parameterList[i]; - fparam->type = fparam->type->addStorageClass(fparam->storageClass); - fparam->storageClass &= ~(STC_TYPECTOR | STCin); - } - //printf("\t-> this = %d, ", t->ty); t->print(); - //printf("\t-> tparam = %d, ", tparam->ty); tparam->print(); - - /* See if tuple match - */ - if (nfparams > 0 && nfargs >= nfparams - 1) - { - /* See if 'A' of the template parameter matches 'A' - * of the type of the last function parameter. - */ - Parameter *fparam = tp->parameterList[nfparams - 1]; - assert(fparam); - assert(fparam->type); - if (fparam->type->ty != Tident) - goto L1; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (tid->idents.length) - goto L1; - - /* Look through parameters to find tuple matching tid->ident - */ - size_t tupi = 0; - for (; 1; tupi++) - { - if (tupi == parameters->length) - goto L1; - TemplateParameter *tx = (*parameters)[tupi]; - TemplateTupleParameter *tup = tx->isTemplateTupleParameter(); - if (tup && tup->ident->equals(tid->ident)) - break; - } - - /* The types of the function arguments [nfparams - 1 .. nfargs] - * now form the tuple argument. - */ - size_t tuple_dim = nfargs - (nfparams - 1); - - /* See if existing tuple, and whether it matches or not - */ - RootObject *o = (*dedtypes)[tupi]; - if (o) - { - // Existing deduced argument must be a tuple, and must match - Tuple *tup = isTuple(o); - if (!tup || tup->objects.length != tuple_dim) - { - result = MATCHnomatch; - return; - } - for (size_t i = 0; i < tuple_dim; i++) - { - Parameter *arg = t->parameterList[nfparams - 1 + i]; - if (!arg->type->equals(tup->objects[i])) - { - result = MATCHnomatch; - return; - } - } - } - else - { - // Create new tuple - Tuple *tup = new Tuple(); - tup->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { - Parameter *arg = t->parameterList[nfparams - 1 + i]; - tup->objects[i] = arg->type; - } - (*dedtypes)[tupi] = tup; - } - nfparams--; // don't consider the last parameter for type deduction - goto L2; - } - - L1: - if (nfargs != nfparams) - { - result = MATCHnomatch; - return; - } - L2: - for (size_t i = 0; i < nfparams; i++) - { - Parameter *a = t->parameterList[i]; - Parameter *ap = tp->parameterList[i]; - - if (!a->isCovariant(t->isref, ap) || - !deduceType(a->type, sc, ap->type, parameters, dedtypes)) - { - result = MATCHnomatch; - return; - } - } - } - visit((Type *)t); - } - - void visit(TypeIdentifier *t) - { - // Extra check - if (tparam && tparam->ty == Tident) - { - TypeIdentifier *tp = (TypeIdentifier *)tparam; - - for (size_t i = 0; i < t->idents.length; i++) - { - RootObject *id1 = t->idents[i]; - RootObject *id2 = tp->idents[i]; - - if (!id1->equals(id2)) - { - result = MATCHnomatch; - return; - } - } - } - visit((Type *)t); - } - - void visit(TypeInstance *t) - { - // Extra check - if (tparam && tparam->ty == Tinstance && t->tempinst->tempdecl) - { - TemplateDeclaration *tempdecl = t->tempinst->tempdecl->isTemplateDeclaration(); - assert(tempdecl); - - TypeInstance *tp = (TypeInstance *)tparam; - - //printf("tempinst->tempdecl = %p\n", tempdecl); - //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl); - if (!tp->tempinst->tempdecl) - { - //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars()); - - /* Handle case of: - * template Foo(T : sa!(T), alias sa) - */ - size_t i = templateIdentifierLookup(tp->tempinst->name, parameters); - if (i == IDX_NOTFOUND) - { - /* Didn't find it as a parameter identifier. Try looking - * it up and seeing if is an alias. See Bugzilla 1454 - */ - TypeIdentifier *tid = new TypeIdentifier(tp->loc, tp->tempinst->name); - Type *tx; - Expression *e; - Dsymbol *s; - tid->resolve(tp->loc, sc, &e, &tx, &s); - if (tx) - { - s = tx->toDsymbol(sc); - if (TemplateInstance *ti = s ? s->parent->isTemplateInstance() : NULL) - { - // Bugzilla 14290: Try to match with ti->tempecl, - // only when ti is an enclosing instance. - Dsymbol *p = sc->parent; - while (p && p != ti) - p = p->parent; - if (p) - s = ti->tempdecl; - } - } - if (s) - { - s = s->toAlias(); - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { - if (td->overroot) - td = td->overroot; - for (; td; td = td->overnext) - { - if (td == tempdecl) - goto L2; - } - } - } - goto Lnomatch; - } - TemplateParameter *tpx = (*parameters)[i]; - if (!tpx->matchArg(sc, tempdecl, i, parameters, dedtypes, NULL)) - goto Lnomatch; - } - else if (tempdecl != tp->tempinst->tempdecl) - goto Lnomatch; - - L2: - - for (size_t i = 0; 1; i++) - { - //printf("\ttest: tempinst->tiargs[%d]\n", i); - RootObject *o1 = NULL; - if (i < t->tempinst->tiargs->length) - o1 = (*t->tempinst->tiargs)[i]; - else if (i < t->tempinst->tdtypes.length && i < tp->tempinst->tiargs->length) - { - // Pick up default arg - o1 = t->tempinst->tdtypes[i]; - } - else if (i >= tp->tempinst->tiargs->length) - break; - - if (i >= tp->tempinst->tiargs->length) - { - size_t dim = tempdecl->parameters->length - (tempdecl->isVariadic() ? 1 : 0); - while (i < dim && ((*tempdecl->parameters)[i]->dependent || - (*tempdecl->parameters)[i]->hasDefaultArg())) - { - i++; - } - if (i >= dim) - break; // match if all remained parameters are dependent - goto Lnomatch; - } - - RootObject *o2 = (*tp->tempinst->tiargs)[i]; - Type *t2 = isType(o2); - - size_t j = (t2 && t2->ty == Tident && i == tp->tempinst->tiargs->length - 1) - ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; - if (j != IDX_NOTFOUND && j == parameters->length - 1 && - (*parameters)[j]->isTemplateTupleParameter()) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (is(X Y == A!(Z), Z...)) {} - * deduce that Z is a tuple(int, float) - */ - - /* Create tuple from remaining args - */ - Tuple *vt = new Tuple(); - size_t vtdim = (tempdecl->isVariadic() - ? t->tempinst->tiargs->length : t->tempinst->tdtypes.length) - i; - vt->objects.setDim(vtdim); - for (size_t k = 0; k < vtdim; k++) - { - RootObject *o; - if (k < t->tempinst->tiargs->length) - o = (*t->tempinst->tiargs)[i + k]; - else // Pick up default arg - o = t->tempinst->tdtypes[i + k]; - vt->objects[k] = o; - } - - Tuple *v = (Tuple *)(*dedtypes)[j]; - if (v) - { - if (!match(v, vt)) - goto Lnomatch; - } - else - (*dedtypes)[j] = vt; - break; - } - else if (!o1) - break; - - Type *t1 = isType(o1); - Dsymbol *s1 = isDsymbol(o1); - Dsymbol *s2 = isDsymbol(o2); - Expression *e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); - Expression *e2 = isExpression(o2); - - if (t1 && t2) - { - if (!deduceType(t1, sc, t2, parameters, dedtypes)) - goto Lnomatch; - } - else if (e1 && e2) - { - Le: - e1 = e1->ctfeInterpret(); - - /* If it is one of the template parameters for this template, - * we should not attempt to interpret it. It already has a value. - */ - if (e2->op == TOKvar && - (((VarExp *)e2)->var->storage_class & STCtemplateparameter)) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); - if (j != IDX_NOTFOUND) - goto L1; - // The template parameter was not from this template - // (it may be from a parent template, for example) - } - - e2 = expressionSemantic(e2, sc); // Bugzilla 13417 - e2 = e2->ctfeInterpret(); - - //printf("e1 = %s, type = %s %d\n", e1->toChars(), e1->type->toChars(), e1->type->ty); - //printf("e2 = %s, type = %s %d\n", e2->toChars(), e2->type->toChars(), e2->type->ty); - if (!e1->equals(e2)) - { - if (!e2->implicitConvTo(e1->type)) - goto Lnomatch; - - e2 = e2->implicitCastTo(sc, e1->type); - e2 = e2->ctfeInterpret(); - if (!e1->equals(e2)) - goto Lnomatch; - } - } - else if (e1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - L1: - if (j == IDX_NOTFOUND) - { - t2->resolve(((TypeIdentifier *)t2)->loc, sc, &e2, &t2, &s2); - if (e2) - goto Le; - goto Lnomatch; - } - if (!(*parameters)[j]->matchArg(sc, e1, j, parameters, dedtypes, NULL)) - goto Lnomatch; - } - else if (s1 && s2) - { - Ls: - if (!s1->equals(s2)) - goto Lnomatch; - } - else if (s1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == IDX_NOTFOUND) - { - t2->resolve(((TypeIdentifier *)t2)->loc, sc, &e2, &t2, &s2); - if (s2) - goto Ls; - goto Lnomatch; - } - if (!(*parameters)[j]->matchArg(sc, s1, j, parameters, dedtypes, NULL)) - goto Lnomatch; - } - else - goto Lnomatch; - } - } - visit((Type *)t); - return; - - Lnomatch: - //printf("no match\n"); - result = MATCHnomatch; - } - - void visit(TypeStruct *t) - { - /* If this struct is a template struct, and we're matching - * it against a template instance, convert the struct type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = t->sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - if (ti && ti->toAlias() == t->sym) - { - TypeInstance *tx = new TypeInstance(Loc(), ti); - result = deduceType(tx, sc, tparam, parameters, dedtypes, wm); - return; - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.length) - { - RootObject *id = tpi->idents[tpi->idents.length - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && t->sym->ident->equals((Identifier *)id)) - { - Type *tparent = t->sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.length--; - result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm); - tpi->idents.length++; - return; - } - } - } - } - - // Extra check - if (tparam && tparam->ty == Tstruct) - { - TypeStruct *tp = (TypeStruct *)tparam; - - //printf("\t%d\n", (MATCH) t->implicitConvTo(tp)); - if (wm && t->deduceWild(tparam, false)) - { - result = MATCHconst; - return; - } - result = t->implicitConvTo(tp); - return; - } - visit((Type *)t); - } - - void visit(TypeEnum *t) - { - // Extra check - if (tparam && tparam->ty == Tenum) - { - TypeEnum *tp = (TypeEnum *)tparam; - if (t->sym == tp->sym) - visit((Type *)t); - else - result = MATCHnomatch; - return; - } - Type *tb = t->toBasetype(); - if (tb->ty == tparam->ty || - (tb->ty == Tsarray && tparam->ty == Taarray)) - { - result = deduceType(tb, sc, tparam, parameters, dedtypes, wm); - return; - } - visit((Type *)t); - } - - /* Helper for TypeClass::deduceType(). - * Classes can match with implicit conversion to a base class or interface. - * This is complicated, because there may be more than one base class which - * matches. In such cases, one or more parameters remain ambiguous. - * For example, - * - * interface I(X, Y) {} - * class C : I(uint, double), I(char, double) {} - * C x; - * foo(T, U)( I!(T, U) x) - * - * deduces that U is double, but T remains ambiguous (could be char or uint). - * - * Given a baseclass b, and initial deduced types 'dedtypes', this function - * tries to match tparam with b, and also tries all base interfaces of b. - * If a match occurs, numBaseClassMatches is incremented, and the new deduced - * types are ANDed with the current 'best' estimate for dedtypes. - */ - static void deduceBaseClassParameters(BaseClass *b, - Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, - Objects *best, int &numBaseClassMatches) - { - TemplateInstance *parti = b->sym ? b->sym->parent->isTemplateInstance() : NULL; - if (parti) - { - // Make a temporary copy of dedtypes so we don't destroy it - Objects *tmpdedtypes = new Objects(); - tmpdedtypes->setDim(dedtypes->length); - memcpy(tmpdedtypes->tdata(), dedtypes->tdata(), dedtypes->length * sizeof(void *)); - - TypeInstance *t = new TypeInstance(Loc(), parti); - MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes); - if (m > MATCHnomatch) - { - // If this is the first ever match, it becomes our best estimate - if (numBaseClassMatches==0) - memcpy(best->tdata(), tmpdedtypes->tdata(), tmpdedtypes->length * sizeof(void *)); - else for (size_t k = 0; k < tmpdedtypes->length; ++k) - { - // If we've found more than one possible type for a parameter, - // mark it as unknown. - if ((*tmpdedtypes)[k] != (*best)[k]) - (*best)[k] = (*dedtypes)[k]; - } - ++numBaseClassMatches; - } - } - // Now recursively test the inherited interfaces - for (size_t j = 0; j < b->baseInterfaces.length; ++j) - { - BaseClass *bi = &b->baseInterfaces.ptr[j]; - deduceBaseClassParameters(bi, - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - - } - - void visit(TypeClass *t) - { - //printf("TypeClass::deduceType(this = %s)\n", t->toChars()); - - /* If this class is a template class, and we're matching - * it against a template instance, convert the class type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = t->sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - if (ti && ti->toAlias() == t->sym) - { - TypeInstance *tx = new TypeInstance(Loc(), ti); - MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm); - // Even if the match fails, there is still a chance it could match - // a base class. - if (m != MATCHnomatch) - { - result = m; - return; - } - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.length) - { - RootObject *id = tpi->idents[tpi->idents.length - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && t->sym->ident->equals((Identifier *)id)) - { - Type *tparent = t->sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.length--; - result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm); - tpi->idents.length++; - return; - } - } - } - - // If it matches exactly or via implicit conversion, we're done - visit((Type *)t); - if (result != MATCHnomatch) - return; - - /* There is still a chance to match via implicit conversion to - * a base class or interface. Because there could be more than one such - * match, we need to check them all. - */ - - int numBaseClassMatches = 0; // Have we found an interface match? - - // Our best guess at dedtypes - Objects *best = new Objects(); - best->setDim(dedtypes->length); - - ClassDeclaration *s = t->sym; - while (s && s->baseclasses->length > 0) - { - // Test the base class - deduceBaseClassParameters((*s->baseclasses)[0], - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - - // Test the interfaces inherited by the base class - for (size_t i = 0; i < s->interfaces.length; ++i) - { - BaseClass *b = s->interfaces.ptr[i]; - deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - s = (*s->baseclasses)[0]->sym; - } - - if (numBaseClassMatches == 0) - { - result = MATCHnomatch; - return; - } - - // If we got at least one match, copy the known types into dedtypes - memcpy(dedtypes->tdata(), best->tdata(), best->length * sizeof(void *)); - result = MATCHconvert; - return; - } - - // Extra check - if (tparam && tparam->ty == Tclass) - { - TypeClass *tp = (TypeClass *)tparam; - - //printf("\t%d\n", (MATCH) t->implicitConvTo(tp)); - if (wm && t->deduceWild(tparam, false)) - { - result = MATCHconst; - return; - } - result = t->implicitConvTo(tp); - return; - } - visit((Type *)t); - } - - void visit(Expression *e) - { - //printf("Expression::deduceType(e = %s)\n", e->toChars()); - size_t i = templateParameterLookup(tparam, parameters); - if (i == IDX_NOTFOUND || ((TypeIdentifier *)tparam)->idents.length > 0) - { - if (e == emptyArrayElement && tparam->ty == Tarray) - { - Type *tn = ((TypeNext *)tparam)->next; - result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm); - return; - } - e->type->accept(this); - return; - } - - TemplateTypeParameter *tp = (*parameters)[i]->isTemplateTypeParameter(); - if (!tp) - return; // nomatch - - if (e == emptyArrayElement) - { - if ((*dedtypes)[i]) - { - result = MATCHexact; - return; - } - if (tp->defaultType) - { - tp->defaultType->accept(this); - return; - } - } - - Type *at = (Type *)(*dedtypes)[i]; - Type *tt; - if (unsigned char wx = deduceWildHelper(e->type, &tt, tparam)) - { - *wm |= wx; - result = MATCHconst; - } - else if (MATCH m = deduceTypeHelper(e->type, &tt, tparam)) - { - result = m; - } - else - return; // nomatch - - // expression vs (none) - if (!at) - { - (*dedtypes)[i] = new TypeDeduced(tt, e, tparam); - return; - } - - TypeDeduced *xt = NULL; - if (at->ty == Tnone) - { - xt = (TypeDeduced *)at; - at = xt->tded; - } - - // From previous matched expressions to current deduced type - MATCH match1 = xt ? xt->matchAll(tt) : MATCHnomatch; - - // From current expresssion to previous deduced type - Type *pt = at->addMod(tparam->mod); - if (*wm) - pt = pt->substWildTo(*wm); - MATCH match2 = e->implicitConvTo(pt); - - if (match1 > MATCHnomatch && match2 > MATCHnomatch) - { - if (at->implicitConvTo(tt) <= MATCHnomatch) - match1 = MATCHnomatch; // Prefer at - else if (tt->implicitConvTo(at) <= MATCHnomatch) - match2 = MATCHnomatch; // Prefer tt - else if (tt->isTypeBasic() && tt->ty == at->ty && tt->mod != at->mod) - { - if (!tt->isMutable() && !at->isMutable()) - tt = tt->mutableOf()->addMod(MODmerge(tt->mod, at->mod)); - else if (tt->isMutable()) - { - if (at->mod == 0) // Prefer unshared - match1 = MATCHnomatch; - else - match2 = MATCHnomatch; - } - else if (at->isMutable()) - { - if (tt->mod == 0) // Prefer unshared - match2 = MATCHnomatch; - else - match1 = MATCHnomatch; - } - //printf("tt = %s, at = %s\n", tt->toChars(), at->toChars()); - } - else - { - match1 = MATCHnomatch; - match2 = MATCHnomatch; - } - } - if (match1 > MATCHnomatch) - { - // Prefer current match: tt - if (xt) - xt->update(tt, e, tparam); - else - (*dedtypes)[i] = tt; - result = match1; - return; - } - if (match2 > MATCHnomatch) - { - // Prefer previous match: (*dedtypes)[i] - if (xt) - xt->update(e, tparam); - result = match2; - return; - } - - /* Deduce common type - */ - if (Type *t = rawTypeMerge(at, tt)) - { - if (xt) - xt->update(t, e, tparam); - else - (*dedtypes)[i] = t; - - pt = tt->addMod(tparam->mod); - if (*wm) - pt = pt->substWildTo(*wm); - result = e->implicitConvTo(pt); - return; - } - - result = MATCHnomatch; - } - - MATCH deduceEmptyArrayElement() - { - if (!emptyArrayElement) - { - emptyArrayElement = new IdentifierExp(Loc(), Id::p); // dummy - emptyArrayElement->type = Type::tvoid; - } - assert(tparam->ty == Tarray); - - Type *tn = ((TypeNext *)tparam)->next; - return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm); - } - - void visit(NullExp *e) - { - if (tparam->ty == Tarray && e->type->ty == Tnull) - { - // tparam:T[] <- e:null (void[]) - result = deduceEmptyArrayElement(); - return; - } - visit((Expression *)e); - } - - void visit(StringExp *e) - { - Type *taai; - if (e->type->ty == Tarray && - (tparam->ty == Tsarray || - (tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident && - ((TypeIdentifier *)taai)->idents.length == 0))) - { - // Consider compile-time known boundaries - e->type->nextOf()->sarrayOf(e->len)->accept(this); - return; - } - visit((Expression *)e); - } - - void visit(ArrayLiteralExp *e) - { - // https://issues.dlang.org/show_bug.cgi?id=20092 - if (e->elements && e->elements->length && - e->type->toBasetype()->nextOf()->ty == Tvoid) - { - result = deduceEmptyArrayElement(); - return; - } - if ((!e->elements || !e->elements->length) && - e->type->toBasetype()->nextOf()->ty == Tvoid && - tparam->ty == Tarray) - { - // tparam:T[] <- e:[] (void[]) - result = deduceEmptyArrayElement(); - return; - } - - if (tparam->ty == Tarray && e->elements && e->elements->length) - { - Type *tn = ((TypeDArray *)tparam)->next; - result = MATCHexact; - if (e->basis) - { - MATCH m = deduceType(e->basis, sc, tn, parameters, dedtypes, wm); - if (m < result) - result = m; - } - for (size_t i = 0; i < e->elements->length; i++) - { - if (result <= MATCHnomatch) - break; - Expression *el = (*e->elements)[i]; - if (!el) - continue; - MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm); - if (m < result) - result = m; - } - return; - } - - Type *taai; - if (e->type->ty == Tarray && - (tparam->ty == Tsarray || - (tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident && - ((TypeIdentifier *)taai)->idents.length == 0))) - { - // Consider compile-time known boundaries - e->type->nextOf()->sarrayOf(e->elements->length)->accept(this); - return; - } - visit((Expression *)e); - } - - void visit(AssocArrayLiteralExp *e) - { - if (tparam->ty == Taarray && e->keys && e->keys->length) - { - TypeAArray *taa = (TypeAArray *)tparam; - result = MATCHexact; - for (size_t i = 0; i < e->keys->length; i++) - { - MATCH m1 = deduceType((*e->keys)[i], sc, taa->index, parameters, dedtypes, wm); - if (m1 < result) - result = m1; - if (result <= MATCHnomatch) - break; - MATCH m2 = deduceType((*e->values)[i], sc, taa->next, parameters, dedtypes, wm); - if (m2 < result) - result = m2; - if (result <= MATCHnomatch) - break; - } - return; - } - visit((Expression *)e); - } - - void visit(FuncExp *e) - { - //printf("e->type = %s, tparam = %s\n", e->type->toChars(), tparam->toChars()); - if (e->td) - { - Type *to = tparam; - if (!to->nextOf() || to->nextOf()->ty != Tfunction) - return; - TypeFunction *tof = (TypeFunction *)to->nextOf(); - - // Parameter types inference from 'tof' - assert(e->td->_scope); - TypeFunction *tf = (TypeFunction *)e->fd->type; - //printf("\ttof = %s\n", tof->toChars()); - //printf("\ttf = %s\n", tf->toChars()); - size_t dim = tf->parameterList.length(); - - if (tof->parameterList.length() != dim || - tof->parameterList.varargs != tf->parameterList.varargs) - return; - - Objects *tiargs = new Objects(); - tiargs->reserve(e->td->parameters->length); - - for (size_t i = 0; i < e->td->parameters->length; i++) - { - TemplateParameter *tp = (*e->td->parameters)[i]; - size_t u = 0; - for (; u < dim; u++) - { - Parameter *p = tf->parameterList[u]; - if (p->type->ty == Tident && - ((TypeIdentifier *)p->type)->ident == tp->ident) - { - break; - } - } - assert(u < dim); - Parameter *pto = tof->parameterList[u]; - if (!pto) - break; - Type *t = pto->type->syntaxCopy(); // Bugzilla 11774 - if (reliesOnTident(t, parameters, inferStart)) - return; - t = typeSemantic(t, e->loc, sc); - if (t->ty == Terror) - return; - tiargs->push(t); - } - - // Set target of return type inference - if (!tf->next && tof->next) - e->fd->treq = tparam; - - TemplateInstance *ti = new TemplateInstance(e->loc, e->td, tiargs); - Expression *ex = new ScopeExp(e->loc, ti); - ex = expressionSemantic(ex, e->td->_scope); - - // Reset inference target for the later re-semantic - e->fd->treq = NULL; - - if (ex->op == TOKerror) - return; - if (ex->op != TOKfunction) - return; - visit(ex->type); - return; - } - - Type *t = e->type; - - if (t->ty == Tdelegate && tparam->ty == Tpointer) - return; - - // Allow conversion from implicit function pointer to delegate - if (e->tok == TOKreserved && - t->ty == Tpointer && tparam->ty == Tdelegate) - { - TypeFunction *tf = (TypeFunction *)t->nextOf(); - t = (new TypeDelegate(tf))->merge(); - } - //printf("tparam = %s <= e->type = %s, t = %s\n", tparam->toChars(), e->type->toChars(), t->toChars()); - visit(t); - } - - void visit(SliceExp *e) - { - Type *taai; - if (e->type->ty == Tarray && - (tparam->ty == Tsarray || - (tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident && - ((TypeIdentifier *)taai)->idents.length == 0))) - { - // Consider compile-time known boundaries - if (Type *tsa = toStaticArrayType(e)) - { - tsa->accept(this); - return; - } - } - visit((Expression *)e); - } - - void visit(CommaExp *e) - { - ((CommaExp *)e)->e2->accept(this); - } - }; - - DeduceType v(sc, tparam, parameters, dedtypes, wm, inferStart); - if (Type *t = isType(o)) - t->accept(&v); - else - { - assert(isExpression(o) && wm); - ((Expression *)o)->accept(&v); - } - return v.result; -} - -/******************************* - * Input: - * t Tested type, if NULL, returns NULL. - * tparams Optional template parameters. - * == NULL: - * If one of the subtypes of this type is a TypeIdentifier, - * i.e. it's an unresolved type, return that type. - * != NULL: - * Only when the TypeIdentifier is one of template parameters, - * return that type. - */ - -bool reliesOnTident(Type *t, TemplateParameters *tparams, size_t iStart) -{ - class ReliesOnTident : public Visitor - { - public: - TemplateParameters *tparams; - size_t iStart; - bool result; - - ReliesOnTident(TemplateParameters *tparams, size_t iStart) - : tparams(tparams), iStart(iStart) - { - result = false; - } - - void visit(Type *) - { - } - - void visit(TypeNext *t) - { - t->next->accept(this); - } - - void visit(TypeVector *t) - { - t->basetype->accept(this); - } - - void visit(TypeAArray *t) - { - visit((TypeNext *)t); - if (!result) - t->index->accept(this); - } - - void visit(TypeFunction *t) - { - size_t dim = t->parameterList.length(); - for (size_t i = 0; i < dim; i++) - { - Parameter *fparam = t->parameterList[i]; - fparam->type->accept(this); - if (result) - return; - } - if (t->next) - t->next->accept(this); - } - - void visit(TypeIdentifier *t) - { - if (!tparams) - { - result = true; - return; - } - - for (size_t i = iStart; i < tparams->length; i++) - { - TemplateParameter *tp = (*tparams)[i]; - if (tp->ident->equals(t->ident)) - { - result = true; - return; - } - } - } - - void visit(TypeInstance *t) - { - if (!tparams) - return; - - for (size_t i = iStart; i < tparams->length; i++) - { - TemplateParameter *tp = (*tparams)[i]; - if (t->tempinst->name == tp->ident) - { - result = true; - return; - } - } - if (!t->tempinst->tiargs) - return; - for (size_t i = 0; i < t->tempinst->tiargs->length; i++) - { - Type *ta = isType((*t->tempinst->tiargs)[i]); - if (ta) - { - ta->accept(this); - if (result) - return; - } - } - } - - void visit(TypeTypeof *t) - { - //printf("TypeTypeof::reliesOnTident('%s')\n", t->toChars()); - t->exp->accept(this); - } - - void visit(TypeTuple *t) - { - if (t->arguments) - { - for (size_t i = 0; i < t->arguments->length; i++) - { - Parameter *arg = (*t->arguments)[i]; - arg->type->accept(this); - if (result) - return; - } - } - } - - void visit(Expression *) - { - //printf("Expression::reliesOnTident('%s')\n", e->toChars()); - } - - void visit(IdentifierExp *e) - { - //printf("IdentifierExp::reliesOnTident('%s')\n", e->toChars()); - for (size_t i = iStart; i < tparams->length; i++) - { - TemplateParameter *tp = (*tparams)[i]; - if (e->ident == tp->ident) - { - result = true; - return; - } - } - } - - void visit(TupleExp *e) - { - //printf("TupleExp::reliesOnTident('%s')\n", e->toChars()); - if (e->exps) - { - for (size_t i = 0; i < e->exps->length; i++) - { - Expression *ea = (*e->exps)[i]; - ea->accept(this); - if (result) - return; - } - } - } - - void visit(ArrayLiteralExp *e) - { - //printf("ArrayLiteralExp::reliesOnTident('%s')\n", e->toChars()); - if (e->elements) - { - for (size_t i = 0; i < e->elements->length; i++) - { - Expression *el = (*e->elements)[i]; - el->accept(this); - if (result) - return; - } - } - } - - void visit(AssocArrayLiteralExp *e) - { - //printf("AssocArrayLiteralExp::reliesOnTident('%s')\n", e->toChars()); - for (size_t i = 0; i < e->keys->length; i++) - { - Expression *ek = (*e->keys)[i]; - ek->accept(this); - if (result) - return; - } - for (size_t i = 0; i < e->values->length; i++) - { - Expression *ev = (*e->values)[i]; - ev->accept(this); - if (result) - return; - } - } - - void visit(StructLiteralExp *e) - { - //printf("StructLiteralExp::reliesOnTident('%s')\n", e->toChars()); - if (e->elements) - { - for (size_t i = 0; i < e->elements->length; i++) - { - Expression *ea = (*e->elements)[i]; - ea->accept(this); - if (result) - return; - } - } - } - - void visit(TypeExp *e) - { - //printf("TypeExp::reliesOnTident('%s')\n", e->toChars()); - e->type->accept(this); - } - - void visit(NewExp *e) - { - //printf("NewExp::reliesOnTident('%s')\n", e->toChars()); - if (e->thisexp) - e->thisexp->accept(this); - if (!result && e->newargs) - { - for (size_t i = 0; i < e->newargs->length; i++) - { - Expression *ea = (*e->newargs)[i]; - ea->accept(this); - if (result) - return; - } - } - e->newtype->accept(this); - if (!result && e->arguments) - { - for (size_t i = 0; i < e->arguments->length; i++) - { - Expression *ea = (*e->arguments)[i]; - ea->accept(this); - if (result) - return; - } - } - } - - void visit(NewAnonClassExp *) - { - //printf("NewAnonClassExp::reliesOnTident('%s')\n", e->toChars()); - result = true; - } - - void visit(FuncExp *) - { - //printf("FuncExp::reliesOnTident('%s')\n", e->toChars()); - result = true; - } - - void visit(TypeidExp *e) - { - //printf("TypeidExp::reliesOnTident('%s')\n", e->toChars()); - if (Expression *ea = isExpression(e->obj)) - ea->accept(this); - else if (Type *ta = isType(e->obj)) - ta->accept(this); - } - - void visit(TraitsExp *e) - { - //printf("TraitsExp::reliesOnTident('%s')\n", e->toChars()); - if (e->args) - { - for (size_t i = 0; i < e->args->length; i++) - { - RootObject *oa = (*e->args)[i]; - if (Expression *ea = isExpression(oa)) - ea->accept(this); - else if (Type *ta = isType(oa)) - ta->accept(this); - if (result) - return; - } - } - } - - void visit(IsExp *e) - { - //printf("IsExp::reliesOnTident('%s')\n", e->toChars()); - e->targ->accept(this); - } - - void visit(UnaExp *e) - { - //printf("UnaExp::reliesOnTident('%s')\n", e->toChars()); - e->e1->accept(this); - } - - void visit(DotTemplateInstanceExp *e) - { - //printf("DotTemplateInstanceExp::reliesOnTident('%s')\n", e->toChars()); - visit((UnaExp *)e); - if (!result && e->ti->tiargs) - { - for (size_t i = 0; i < e->ti->tiargs->length; i++) - { - RootObject *oa = (*e->ti->tiargs)[i]; - if (Expression *ea = isExpression(oa)) - ea->accept(this); - else if (Type *ta = isType(oa)) - ta->accept(this); - if (result) - return; - } - } - } - - void visit(CallExp *e) - { - //printf("CallExp::reliesOnTident('%s')\n", e->toChars()); - visit((UnaExp *)e); - if (!result && e->arguments) - { - for (size_t i = 0; i < e->arguments->length; i++) - { - Expression *ea = (*e->arguments)[i]; - ea->accept(this); - if (result) - return; - } - } - } - - void visit(CastExp *e) - { - //printf("CastExp::reliesOnTident('%s')\n", e->toChars()); - visit((UnaExp *)e); - // e.to can be null for cast() with no type - if (!result && e->to) - e->to->accept(this); - } - - void visit(SliceExp *e) - { - //printf("SliceExp::reliesOnTident('%s')\n", e->toChars()); - visit((UnaExp *)e); - if (!result && e->lwr) - e->lwr->accept(this); - if (!result && e->upr) - e->upr->accept(this); - } - - void visit(IntervalExp *e) - { - //printf("IntervalExp::reliesOnTident('%s')\n", e->toChars()); - e->lwr->accept(this); - if (!result) - e->upr->accept(this); - } - - void visit(ArrayExp *e) - { - //printf("ArrayExp::reliesOnTident('%s')\n", e->toChars()); - visit((UnaExp *)e); - if (!result && e->arguments) - { - for (size_t i = 0; i < e->arguments->length; i++) - { - Expression *ea = (*e->arguments)[i]; - ea->accept(this); - } - } - } - - void visit(BinExp *e) - { - //printf("BinExp::reliesOnTident('%s')\n", e->toChars()); - e->e1->accept(this); - if (!result) - e->e2->accept(this); - } - - void visit(CondExp *e) - { - //printf("BinExp::reliesOnTident('%s')\n", e->toChars()); - e->econd->accept(this); - if (!result) - visit((BinExp *)e); - } - }; - - if (!t) - return false; - - ReliesOnTident v(tparams, iStart); - t->accept(&v); - return v.result; -} - -/* ======================== TemplateParameter =============================== */ - -TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) -{ - this->loc = loc; - this->ident = ident; - this->dependent = false; -} - -TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter() -{ - return NULL; -} - -TemplateValueParameter *TemplateParameter::isTemplateValueParameter() -{ - return NULL; -} - -TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter() -{ - return NULL; -} - -TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() -{ - return NULL; -} - -TemplateThisParameter *TemplateParameter::isTemplateThisParameter() -{ - return NULL; -} - -/******************************************* - * Match to a particular TemplateParameter. - * Input: - * instLoc location that the template is instantiated. - * tiargs[] actual arguments to template instance - * i i'th argument - * parameters[] template parameters - * dedtypes[] deduced arguments to template instance - * *psparam set to symbol declared and initialized to dedtypes[i] - */ -MATCH TemplateParameter::matchArg(Loc instLoc, Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - RootObject *oarg; - - if (i < tiargs->length) - oarg = (*tiargs)[i]; - else - { - // Get default argument instead - oarg = defaultArg(instLoc, sc); - if (!oarg) - { - assert(i < dedtypes->length); - // It might have already been deduced - oarg = (*dedtypes)[i]; - if (!oarg) - goto Lnomatch; - } - } - return matchArg(sc, oarg, i, parameters, dedtypes, psparam); - -Lnomatch: - if (psparam) - *psparam = NULL; - return MATCHnomatch; -} - -/* ======================== TemplateTypeParameter =========================== */ - -// type-parameter - -Type *TemplateTypeParameter::tdummy = NULL; - -TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, - Type *defaultType) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specType = specType; - this->defaultType = defaultType; -} - -TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() -{ - return this; -} - -TemplateParameter *TemplateTypeParameter::syntaxCopy() -{ - return new TemplateTypeParameter(loc, ident, - specType ? specType->syntaxCopy() : NULL, - defaultType ? defaultType->syntaxCopy() : NULL); -} - -bool TemplateTypeParameter::declareParameter(Scope *sc) -{ - //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars()); - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - Declaration *ad = new AliasDeclaration(loc, ident, ti); - return sc->insert(ad) != NULL; -} - -MATCH TemplateTypeParameter::matchArg(Scope *sc, RootObject *oarg, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateTypeParameter::matchArg('%s')\n", ident->toChars()); - MATCH m = MATCHexact; - Type *ta = isType(oarg); - if (!ta) - { - //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); - goto Lnomatch; - } - //printf("ta is %s\n", ta->toChars()); - - if (specType) - { - if (!ta || ta == tdummy) - goto Lnomatch; - - //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); - MATCH m2 = deduceType(ta, sc, specType, parameters, dedtypes); - if (m2 <= MATCHnomatch) - { - //printf("\tfailed deduceType\n"); - goto Lnomatch; - } - - if (m2 < m) - m = m2; - if ((*dedtypes)[i]) - { - Type *t = (Type *)(*dedtypes)[i]; - - if (dependent && !t->equals(ta)) // Bugzilla 14357 - goto Lnomatch; - - /* This is a self-dependent parameter. For example: - * template X(T : T*) {} - * template X(T : S!T, alias S) {} - */ - //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); - ta = t; - } - } - else - { - if ((*dedtypes)[i]) - { - // Must match already deduced type - Type *t = (Type *)(*dedtypes)[i]; - - if (!t->equals(ta)) - { - //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); - goto Lnomatch; - } - } - else - { - // So that matches with specializations are better - m = MATCHconvert; - } - } - (*dedtypes)[i] = ta; - - if (psparam) - *psparam = new AliasDeclaration(loc, ident, ta); - //printf("\tm = %d\n", m); - return dependent ? MATCHexact : m; - -Lnomatch: - if (psparam) - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateTypeParameter::print(RootObject *oarg, RootObject *oded) -{ - printf(" %s\n", ident->toChars()); - - Type *t = isType(oarg); - Type *ta = isType(oded); - - assert(ta); - - if (specType) - printf("\tSpecialization: %s\n", specType->toChars()); - if (defaultType) - printf("\tDefault: %s\n", defaultType->toChars()); - printf("\tParameter: %s\n", t ? t->toChars() : "NULL"); - printf("\tDeduced Type: %s\n", ta->toChars()); -} - -void *TemplateTypeParameter::dummyArg() -{ - Type *t = specType; - if (!t) - { - // Use this for alias-parameter's too (?) - if (!tdummy) - tdummy = new TypeIdentifier(loc, ident); - t = tdummy; - } - return (void *)t; -} - - -RootObject *TemplateTypeParameter::specialization() -{ - return specType; -} - -RootObject *TemplateTypeParameter::defaultArg(Loc, Scope *sc) -{ - Type *t = defaultType; - if (t) - { - t = t->syntaxCopy(); - t = typeSemantic(t, loc, sc); // use the parameter loc - } - return t; -} - -bool TemplateTypeParameter::hasDefaultArg() -{ - return defaultType != NULL; -} - -/* ======================== TemplateThisParameter =========================== */ - -// this-parameter - -TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident, - Type *specType, - Type *defaultType) - : TemplateTypeParameter(loc, ident, specType, defaultType) -{ -} - -TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter() -{ - return this; -} - -TemplateParameter *TemplateThisParameter::syntaxCopy() -{ - return new TemplateThisParameter(loc, ident, - specType ? specType->syntaxCopy() : NULL, - defaultType ? defaultType->syntaxCopy() : NULL); -} - -/* ======================== TemplateAliasParameter ========================== */ - -// alias-parameter - -Dsymbol *TemplateAliasParameter::sdummy = NULL; - -TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, - Type *specType, RootObject *specAlias, RootObject *defaultAlias) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specType = specType; - this->specAlias = specAlias; - this->defaultAlias = defaultAlias; -} - -TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() -{ - return this; -} - -TemplateParameter *TemplateAliasParameter::syntaxCopy() -{ - return new TemplateAliasParameter(loc, ident, - specType ? specType->syntaxCopy() : NULL, - objectSyntaxCopy(specAlias), - objectSyntaxCopy(defaultAlias)); -} - -bool TemplateAliasParameter::declareParameter(Scope *sc) -{ - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - Declaration *ad = new AliasDeclaration(loc, ident, ti); - return sc->insert(ad) != NULL; -} - -MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateAliasParameter::matchArg('%s')\n", ident->toChars()); - MATCH m = MATCHexact; - Type *ta = isType(oarg); - RootObject *sa = ta && !ta->deco ? NULL : getDsymbol(oarg); - Expression *ea = isExpression(oarg); - if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) - sa = ((ThisExp *)ea)->var; - else if (ea && ea->op == TOKscope) - sa = ((ScopeExp *)ea)->sds; - if (sa) - { - if (((Dsymbol *)sa)->isAggregateDeclaration()) - m = MATCHconvert; - - /* specType means the alias must be a declaration with a type - * that matches specType. - */ - if (specType) - { - Declaration *d = ((Dsymbol *)sa)->isDeclaration(); - if (!d) - goto Lnomatch; - if (!d->type->equals(specType)) - goto Lnomatch; - } - } - else - { - sa = oarg; - if (ea) - { - if (specType) - { - if (!ea->type->equals(specType)) - goto Lnomatch; - } - } - else if (ta && ta->ty == Tinstance && !specAlias) - { - /* Bugzilla xxxxx: Specialized parameter should be prefeerd - * match to the template type parameter. - * template X(alias a) {} // a == this - * template X(alias a : B!A, alias B, A...) {} // B!A => ta - */ - } - else if (sa && sa == TemplateTypeParameter::tdummy) - { - /* Bugzilla 2025: Aggregate Types should preferentially - * match to the template type parameter. - * template X(alias a) {} // a == this - * template X(T) {} // T => sa - */ - } - else if (ta && ta->ty != Tident) - { - /* Match any type that's not a TypeIdentifier to alias parameters, - * but prefer type parameter. - * template X(alias a) { } // a == ta - * - * TypeIdentifiers are excluded because they might be not yet resolved aliases. - */ - m = MATCHconvert; - } - else - goto Lnomatch; - } - - if (specAlias) - { - if (sa == sdummy) - goto Lnomatch; - Dsymbol *sx = isDsymbol(sa); - if (sa != specAlias && sx) - { - Type *talias = isType(specAlias); - if (!talias) - goto Lnomatch; - - TemplateInstance *ti = sx->isTemplateInstance(); - if (!ti && sx->parent) - { - ti = sx->parent->isTemplateInstance(); - if (ti && ti->name != sx->ident) - goto Lnomatch; - } - if (!ti) - goto Lnomatch; - - Type *t = new TypeInstance(Loc(), ti); - MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes); - if (m2 <= MATCHnomatch) - goto Lnomatch; - } - } - else if ((*dedtypes)[i]) - { - // Must match already deduced symbol - RootObject *si = (*dedtypes)[i]; - if (!sa || si != sa) - goto Lnomatch; - } - (*dedtypes)[i] = sa; - - if (psparam) - { - if (Dsymbol *s = isDsymbol(sa)) - { - *psparam = new AliasDeclaration(loc, ident, s); - } - else if (Type *t = isType(sa)) - { - *psparam = new AliasDeclaration(loc, ident, t); - } - else - { - assert(ea); - - // Declare manifest constant - Initializer *init = new ExpInitializer(loc, ea); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = STCmanifest; - dsymbolSemantic(v, sc); - *psparam = v; - } - } - return dependent ? MATCHexact : m; - -Lnomatch: - if (psparam) - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateAliasParameter::print(RootObject *, RootObject *oded) -{ - printf(" %s\n", ident->toChars()); - - Dsymbol *sa = isDsymbol(oded); - assert(sa); - - printf("\tParameter alias: %s\n", sa->toChars()); -} - -void *TemplateAliasParameter::dummyArg() -{ - RootObject *s = specAlias; - if (!s) - { - if (!sdummy) - sdummy = new Dsymbol(); - s = sdummy; - } - return (void*)s; -} - - -RootObject *TemplateAliasParameter::specialization() -{ - return specAlias; -} - -RootObject *TemplateAliasParameter::defaultArg(Loc, Scope *sc) -{ - RootObject *da = defaultAlias; - Type *ta = isType(defaultAlias); - if (ta) - { - if (ta->ty == Tinstance) - { - // If the default arg is a template, instantiate for each type - da = ta->syntaxCopy(); - } - } - - RootObject *o = aliasParameterSemantic(loc, sc, da, NULL); // use the parameter loc - return o; -} - -bool TemplateAliasParameter::hasDefaultArg() -{ - return defaultAlias != NULL; -} - -/* ======================== TemplateValueParameter ========================== */ - -// value-parameter - -AA *TemplateValueParameter::edummies = NULL; - -TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, - Expression *specValue, Expression *defaultValue) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->valType = valType; - this->specValue = specValue; - this->defaultValue = defaultValue; -} - -TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() -{ - return this; -} - -TemplateParameter *TemplateValueParameter::syntaxCopy() -{ - return new TemplateValueParameter(loc, ident, - valType->syntaxCopy(), - specValue ? specValue->syntaxCopy() : NULL, - defaultValue ? defaultValue->syntaxCopy() : NULL); -} - -bool TemplateValueParameter::declareParameter(Scope *sc) -{ - VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL); - v->storage_class = STCtemplateparameter; - return sc->insert(v) != NULL; -} - -MATCH TemplateValueParameter::matchArg(Scope *sc, RootObject *oarg, - size_t i, TemplateParameters *, Objects *dedtypes, Declaration **psparam) -{ - //printf("TemplateValueParameter::matchArg('%s')\n", ident->toChars()); - - MATCH m = MATCHexact; - - Expression *ei = isExpression(oarg); - Type *vt; - - if (!ei && oarg) - { - Dsymbol *si = isDsymbol(oarg); - FuncDeclaration *f = si ? si->isFuncDeclaration() : NULL; - if (!f || !f->fbody || f->needThis()) - goto Lnomatch; - - ei = new VarExp(loc, f); - ei = expressionSemantic(ei, sc); - - /* If a function is really property-like, and then - * it's CTFEable, ei will be a literal expression. - */ - unsigned int olderrors = global.startGagging(); - ei = resolveProperties(sc, ei); - ei = ei->ctfeInterpret(); - if (global.endGagging(olderrors) || ei->op == TOKerror) - goto Lnomatch; - - /* Bugzilla 14520: A property-like function can match to both - * TemplateAlias and ValueParameter. But for template overloads, - * it should always prefer alias parameter to be consistent - * template match result. - * - * template X(alias f) { enum X = 1; } - * template X(int val) { enum X = 2; } - * int f1() { return 0; } // CTFEable - * int f2(); // body-less function is not CTFEable - * enum x1 = X!f1; // should be 1 - * enum x2 = X!f2; // should be 1 - * - * e.g. The x1 value must be same even if the f1 definition will be moved - * into di while stripping body code. - */ - m = MATCHconvert; - } - - if (ei && ei->op == TOKvar) - { - // Resolve const variables that we had skipped earlier - ei = ei->ctfeInterpret(); - } - - //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty); - vt = typeSemantic(valType, loc, sc); - //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars()); - //printf("vt = %s\n", vt->toChars()); - - if (ei->type) - { - MATCH m2 = ei->implicitConvTo(vt); - //printf("m: %d\n", m); - if (m2 < m) - m = m2; - if (m <= MATCHnomatch) - goto Lnomatch; - ei = ei->implicitCastTo(sc, vt); - ei = ei->ctfeInterpret(); - } - - if (specValue) - { - if (!ei || (Expression *)dmd_aaGetRvalue(edummies, (void *)ei->type) == ei) - goto Lnomatch; - - Expression *e = specValue; - - sc = sc->startCTFE(); - e = expressionSemantic(e, sc); - e = resolveProperties(sc, e); - sc = sc->endCTFE(); - e = e->implicitCastTo(sc, vt); - e = e->ctfeInterpret(); - - ei = ei->syntaxCopy(); - sc = sc->startCTFE(); - ei = expressionSemantic(ei, sc); - sc = sc->endCTFE(); - ei = ei->implicitCastTo(sc, vt); - ei = ei->ctfeInterpret(); - //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); - //printf("\te : %s, %s\n", e->toChars(), e->type->toChars()); - if (!ei->equals(e)) - goto Lnomatch; - } - else - { - if ((*dedtypes)[i]) - { - // Must match already deduced value - Expression *e = (Expression *)(*dedtypes)[i]; - - if (!ei || !ei->equals(e)) - goto Lnomatch; - } - } - (*dedtypes)[i] = ei; - - if (psparam) - { - Initializer *init = new ExpInitializer(loc, ei); - Declaration *sparam = new VarDeclaration(loc, vt, ident, init); - sparam->storage_class = STCmanifest; - *psparam = sparam; - } - return dependent ? MATCHexact : m; - -Lnomatch: - //printf("\tno match\n"); - if (psparam) - *psparam = NULL; - return MATCHnomatch; -} - - -void TemplateValueParameter::print(RootObject *, RootObject *oded) -{ - printf(" %s\n", ident->toChars()); - - Expression *ea = isExpression(oded); - - if (specValue) - printf("\tSpecialization: %s\n", specValue->toChars()); - printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL"); -} - -void *TemplateValueParameter::dummyArg() -{ - Expression *e = specValue; - if (!e) - { - // Create a dummy value - Expression **pe = (Expression **)dmd_aaGet(&edummies, (void *)valType); - if (!*pe) - *pe = valType->defaultInit(); - e = *pe; - } - return (void *)e; -} - - -RootObject *TemplateValueParameter::specialization() -{ - return specValue; -} - -RootObject *TemplateValueParameter::defaultArg(Loc instLoc, Scope *sc) -{ - Expression *e = defaultValue; - if (e) - { - e = e->syntaxCopy(); - unsigned olderrs = global.errors; - if ((e = expressionSemantic(e, sc)) == NULL) - return NULL; - if ((e = resolveProperties(sc, e)) == NULL) - return NULL; - e = e->resolveLoc(instLoc, sc); // use the instantiated loc - e = e->optimize(WANTvalue); - if (global.errors != olderrs) - e = new ErrorExp(); - } - return e; -} - -bool TemplateValueParameter::hasDefaultArg() -{ - return defaultValue != NULL; -} - -/* ======================== TemplateTupleParameter ========================== */ - -// variadic-parameter - -TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident) - : TemplateParameter(loc, ident) -{ - this->ident = ident; -} - -TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() -{ - return this; -} - -TemplateParameter *TemplateTupleParameter::syntaxCopy() -{ - return new TemplateTupleParameter(loc, ident); -} - -bool TemplateTupleParameter::declareParameter(Scope *sc) -{ - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - Declaration *ad = new AliasDeclaration(loc, ident, ti); - return sc->insert(ad) != NULL; -} - -MATCH TemplateTupleParameter::matchArg(Loc, Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - /* The rest of the actual arguments (tiargs[]) form the match - * for the variadic parameter. - */ - assert(i + 1 == dedtypes->length); // must be the last one - Tuple *ovar; - - if (Tuple *u = isTuple((*dedtypes)[i])) - { - // It has already been deduced - ovar = u; - } - else if (i + 1 == tiargs->length && isTuple((*tiargs)[i])) - ovar = isTuple((*tiargs)[i]); - else - { - ovar = new Tuple(); - //printf("ovar = %p\n", ovar); - if (i < tiargs->length) - { - //printf("i = %d, tiargs->length = %d\n", i, tiargs->length); - ovar->objects.setDim(tiargs->length - i); - for (size_t j = 0; j < ovar->objects.length; j++) - ovar->objects[j] = (*tiargs)[i + j]; - } - } - return matchArg(sc, ovar, i, parameters, dedtypes, psparam); -} - -MATCH TemplateTupleParameter::matchArg(Scope *, RootObject *oarg, - size_t i, TemplateParameters *, Objects *dedtypes, Declaration **psparam) -{ - //printf("TemplateTupleParameter::matchArg('%s')\n", ident->toChars()); - Tuple *ovar = isTuple(oarg); - if (!ovar) - return MATCHnomatch; - if ((*dedtypes)[i]) - { - Tuple *tup = isTuple((*dedtypes)[i]); - if (!tup) - return MATCHnomatch; - if (!match(tup, ovar)) - return MATCHnomatch; - } - (*dedtypes)[i] = ovar; - - if (psparam) - *psparam = new TupleDeclaration(loc, ident, &ovar->objects); - return dependent ? MATCHexact : MATCHconvert; -} - - -void TemplateTupleParameter::print(RootObject *, RootObject *oded) -{ - printf(" %s... [", ident->toChars()); - Tuple *v = isTuple(oded); - assert(v); - - //printf("|%d| ", v->objects.length); - for (size_t i = 0; i < v->objects.length; i++) - { - if (i) - printf(", "); - - RootObject *o = v->objects[i]; - - Dsymbol *sa = isDsymbol(o); - if (sa) - printf("alias: %s", sa->toChars()); - - Type *ta = isType(o); - if (ta) - printf("type: %s", ta->toChars()); - - Expression *ea = isExpression(o); - if (ea) - printf("exp: %s", ea->toChars()); - - assert(!isTuple(o)); // no nested Tuple arguments - } - - printf("]\n"); -} - -void *TemplateTupleParameter::dummyArg() -{ - return NULL; -} - - -RootObject *TemplateTupleParameter::specialization() -{ - return NULL; -} - -RootObject *TemplateTupleParameter::defaultArg(Loc, Scope *) -{ - return NULL; -} - -bool TemplateTupleParameter::hasDefaultArg() -{ - return false; -} - -/* ======================== TemplateInstance ================================ */ - -TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) - : ScopeDsymbol(NULL) -{ - this->loc = loc; - this->name = ident; - this->tiargs = NULL; - this->tempdecl = NULL; - this->inst = NULL; - this->tinst = NULL; - this->tnext = NULL; - this->minst = NULL; - this->deferred = NULL; - this->memberOf = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semantictiargsdone = false; - this->inuse = 0; - this->nest = 0; - this->havetempdecl = false; - this->enclosing = NULL; - this->gagged = false; - this->hash = 0; - this->fargs = NULL; -} - -/***************** - * This constructor is only called when we figured out which function - * template to instantiate. - */ - -TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) - : ScopeDsymbol(NULL) -{ - this->loc = loc; - this->name = td->ident; - this->tiargs = tiargs; - this->tempdecl = td; - this->inst = NULL; - this->tinst = NULL; - this->tnext = NULL; - this->minst = NULL; - this->deferred = NULL; - this->memberOf = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semantictiargsdone = true; - this->inuse = 0; - this->nest = 0; - this->havetempdecl = true; - this->enclosing = NULL; - this->gagged = false; - this->hash = 0; - this->fargs = NULL; - - assert(tempdecl->_scope); -} - - -Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) -{ - Objects *a = NULL; - if (objs) - { - a = new Objects(); - a->setDim(objs->length); - for (size_t i = 0; i < objs->length; i++) - (*a)[i] = objectSyntaxCopy((*objs)[i]); - } - return a; -} - -Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) -{ - TemplateInstance *ti = - s ? (TemplateInstance *)s - : new TemplateInstance(loc, name); - ti->tiargs = arraySyntaxCopy(tiargs); - TemplateDeclaration *td; - if (inst && tempdecl && (td = tempdecl->isTemplateDeclaration()) != NULL) - td->ScopeDsymbol::syntaxCopy(ti); - else - ScopeDsymbol::syntaxCopy(ti); - return ti; -} - -void TemplateInstance::expandMembers(Scope *sc2) -{ - for (size_t i = 0; i < members->length; i++) - { - Dsymbol *s = (*members)[i]; - s->setScope(sc2); - } - - for (size_t i = 0; i < members->length; i++) - { - Dsymbol *s = (*members)[i]; - s->importAll(sc2); - } - - for (size_t i = 0; i < members->length; i++) - { - Dsymbol *s = (*members)[i]; - //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); - //printf("test: enclosing = %d, sc2->parent = %s\n", enclosing, sc2->parent->toChars()); -// if (enclosing) -// s->parent = sc->parent; - //printf("test3: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars()); - dsymbolSemantic(s, sc2); - //printf("test4: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars()); - Module::runDeferredSemantic(); - } -} - -void TemplateInstance::tryExpandMembers(Scope *sc2) -{ - static int nest; - // extracted to a function to allow windows SEH to work without destructors in the same function - //printf("%d\n", nest); - if (++nest > global.recursionLimit) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion exceeded allowed nesting limit"); - fatal(); - } - - expandMembers(sc2); - - nest--; -} - -void TemplateInstance::trySemantic3(Scope *sc2) -{ - // extracted to a function to allow windows SEH to work without destructors in the same function - static int nest; - //printf("%d\n", nest); - if (++nest > global.recursionLimit) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion exceeded allowed nesting limit"); - fatal(); - } - semantic3(this, sc2); - - --nest; -} - -/********************************************** - * Find template declaration corresponding to template instance. - * - * Returns: - * false if finding fails. - * Note: - * This function is reentrant against error occurrence. If returns false, - * any members of this object won't be modified, and repetition call will - * reproduce same error. - */ - -bool TemplateInstance::findTempDecl(Scope *sc, WithScopeSymbol **pwithsym) -{ - if (pwithsym) - *pwithsym = NULL; - - if (havetempdecl) - return true; - - //printf("TemplateInstance::findTempDecl() %s\n", toChars()); - if (!tempdecl) - { - /* Given: - * foo!( ... ) - * figure out which TemplateDeclaration foo refers to. - */ - Identifier *id = name; - Dsymbol *scopesym; - Dsymbol *s = sc->search(loc, id, &scopesym); - if (!s) - { - s = sc->search_correct(id); - if (s) - error("template `%s` is not defined, did you mean %s?", id->toChars(), s->toChars()); - else - error("template `%s` is not defined", id->toChars()); - return false; - } - - if (pwithsym) - *pwithsym = scopesym->isWithScopeSymbol(); - - /* We might have found an alias within a template when - * we really want the template. - */ - TemplateInstance *ti; - if (s->parent && - (ti = s->parent->isTemplateInstance()) != NULL) - { - if (ti->tempdecl && ti->tempdecl->ident == id) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration(); - assert(td); - if (td->overroot) // if not start of overloaded list of TemplateDeclaration's - td = td->overroot; // then get the start - s = td; - } - } - - if (!updateTempDecl(sc, s)) - { - return false; - } - } - assert(tempdecl); - - struct ParamFwdTi - { - static int fp(void *param, Dsymbol *s) - { - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (!td) - return 0; - - TemplateInstance *ti = (TemplateInstance *)param; - if (td->semanticRun == PASSinit) - { - if (td->_scope) - { - // Try to fix forward reference. Ungag errors while doing so. - Ungag ungag = td->ungagSpeculative(); - dsymbolSemantic(td, td->_scope); - } - if (td->semanticRun == PASSinit) - { - ti->error("%s forward references template declaration %s", ti->toChars(), td->toChars()); - return 1; - } - } - return 0; - } - }; - // Look for forward references - OverloadSet *tovers = tempdecl->isOverloadSet(); - size_t overs_dim = tovers ? tovers->a.length : 1; - for (size_t oi = 0; oi < overs_dim; oi++) - { - if (overloadApply(tovers ? tovers->a[oi] : tempdecl, (void *)this, &ParamFwdTi::fp)) - return false; - } - return true; -} - -/********************************************** - * Confirm s is a valid template, then store it. - * Input: - * sc - * s candidate symbol of template. It may be: - * TemplateDeclaration - * FuncDeclaration with findTemplateDeclRoot() != NULL - * OverloadSet which contains candidates - * Returns: - * true if updating succeeds. - */ - -bool TemplateInstance::updateTempDecl(Scope *sc, Dsymbol *s) -{ - if (s) - { - Identifier *id = name; - s = s->toAlias(); - - /* If an OverloadSet, look for a unique member that is a template declaration - */ - OverloadSet *os = s->isOverloadSet(); - if (os) - { - s = NULL; - for (size_t i = 0; i < os->a.length; i++) - { - Dsymbol *s2 = os->a[i]; - if (FuncDeclaration *f = s2->isFuncDeclaration()) - s2 = f->findTemplateDeclRoot(); - else - s2 = s2->isTemplateDeclaration(); - if (s2) - { - if (s) - { - tempdecl = os; - return true; - } - s = s2; - } - } - if (!s) - { - error("template `%s` is not defined", id->toChars()); - return false; - } - } - - OverDeclaration *od = s->isOverDeclaration(); - if (od) - { - tempdecl = od; // TODO: more strict check - return true; - } - - /* It should be a TemplateDeclaration, not some other symbol - */ - if (FuncDeclaration *f = s->isFuncDeclaration()) - tempdecl = f->findTemplateDeclRoot(); - else - tempdecl = s->isTemplateDeclaration(); - if (!tempdecl) - { - if (!s->parent && global.errors) - return false; - if (!s->parent && s->getType()) - { - Dsymbol *s2 = s->getType()->toDsymbol(sc); - if (!s2) - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return false; - } - s = s2; - } - //assert(s->parent); - TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; - if (ti && - (ti->name == s->ident || - ti->toAlias()->ident == s->ident) - && - ti->tempdecl) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration(); - assert(td); - if (td->overroot) // if not start of overloaded list of TemplateDeclaration's - td = td->overroot; // then get the start - tempdecl = td; - } - else - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return false; - } - } - } - return (tempdecl != NULL); -} - -/********************************** - * Run semantic on the elements of tiargs. - * Input: - * sc - * Returns: - * false if one or more arguments have errors. - * Note: - * This function is reentrant against error occurrence. If returns false, - * all elements of tiargs won't be modified. - */ - -bool TemplateInstance::semanticTiargs(Scope *sc) -{ - //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); - if (semantictiargsdone) - return true; - if (semanticTiargs(loc, sc, tiargs, 0)) - { - // cache the result iff semantic analysis succeeded entirely - semantictiargsdone = 1; - return true; - } - return false; -} - -/********************************** - * Run semantic of tiargs as arguments of template. - * Input: - * loc - * sc - * tiargs array of template arguments - * flags 1: replace const variables with their initializers - * 2: don't devolve Parameter to Type - * Returns: - * false if one or more arguments have errors. - */ - -bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags) -{ - // Run semantic on each argument, place results in tiargs[] - //printf("+TemplateInstance::semanticTiargs()\n"); - if (!tiargs) - return true; - bool err = false; - for (size_t j = 0; j < tiargs->length; j++) - { - RootObject *o = (*tiargs)[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - - //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); - if (ta) - { - //printf("type %s\n", ta->toChars()); - - // It might really be an Expression or an Alias - ta->resolve(loc, sc, &ea, &ta, &sa, (flags & 1) != 0); - if (ea) goto Lexpr; - if (sa) goto Ldsym; - if (ta == NULL) - { - assert(global.errors); - ta = Type::terror; - } - - Ltype: - if (ta->ty == Ttuple) - { - // Expand tuple - TypeTuple *tt = (TypeTuple *)ta; - size_t dim = tt->arguments->length; - tiargs->remove(j); - if (dim) - { - tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - { - Parameter *arg = (*tt->arguments)[i]; - if (flags & 2 && (arg->ident || arg->userAttribDecl)) - tiargs->insert(j + i, arg); - else - tiargs->insert(j + i, arg->type); - } - } - j--; - continue; - } - if (ta->ty == Terror) - { - err = true; - continue; - } - (*tiargs)[j] = ta->merge2(); - } - else if (ea) - { - Lexpr: - //printf("+[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars()); - if (flags & 1) // only used by __traits - { - ea = expressionSemantic(ea, sc); - - // must not interpret the args, excepting template parameters - if (ea->op != TOKvar || - (((VarExp *)ea)->var->storage_class & STCtemplateparameter)) - { - ea = ea->optimize(WANTvalue); - } - } - else - { - sc = sc->startCTFE(); - ea = expressionSemantic(ea, sc); - sc = sc->endCTFE(); - - if (ea->op == TOKvar) - { - /* This test is to skip substituting a const var with - * its initializer. The problem is the initializer won't - * match with an 'alias' parameter. Instead, do the - * const substitution in TemplateValueParameter::matchArg(). - */ - } - else if (definitelyValueParameter(ea)) - { - if (ea->checkValue()) // check void expression - ea = new ErrorExp(); - unsigned int olderrs = global.errors; - ea = ea->ctfeInterpret(); - if (global.errors != olderrs) - ea = new ErrorExp(); - } - } - //printf("-[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars()); - if (ea->op == TOKtuple) - { - // Expand tuple - TupleExp *te = (TupleExp *)ea; - size_t dim = te->exps->length; - tiargs->remove(j); - if (dim) - { - tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - tiargs->insert(j + i, (*te->exps)[i]); - } - j--; - continue; - } - if (ea->op == TOKerror) - { - err = true; - continue; - } - (*tiargs)[j] = ea; - - if (ea->op == TOKtype) - { - ta = ea->type; - goto Ltype; - } - if (ea->op == TOKscope) - { - sa = ((ScopeExp *)ea)->sds; - goto Ldsym; - } - if (ea->op == TOKfunction) - { - FuncExp *fe = (FuncExp *)ea; - /* A function literal, that is passed to template and - * already semanticed as function pointer, never requires - * outer frame. So convert it to global function is valid. - */ - if (fe->fd->tok == TOKreserved && fe->type->ty == Tpointer) - { - // change to non-nested - fe->fd->tok = TOKfunction; - fe->fd->vthis = NULL; - } - else if (fe->td) - { - /* If template argument is a template lambda, - * get template declaration itself. */ - //sa = fe->td; - //goto Ldsym; - } - } - if (ea->op == TOKdotvar && !(flags & 1)) - { - // translate expression to dsymbol. - sa = ((DotVarExp *)ea)->var; - goto Ldsym; - } - if (ea->op == TOKtemplate) - { - sa = ((TemplateExp *)ea)->td; - goto Ldsym; - } - if (ea->op == TOKdottd && !(flags & 1)) - { - // translate expression to dsymbol. - sa = ((DotTemplateExp *)ea)->td; - goto Ldsym; - } - if (ea->op == TOKdot) - { - if (ScopeExp *se = ((DotExp *)ea)->e2->isScopeExp()) - { - sa = se->sds; - goto Ldsym; - } - } - } - else if (sa) - { - Ldsym: - //printf("dsym %s %s\n", sa->kind(), sa->toChars()); - if (sa->errors) - { - err = true; - continue; - } - - TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); - if (d) - { - // Expand tuple - tiargs->remove(j); - tiargs->insert(j, d->objects); - j--; - continue; - } - if (FuncAliasDeclaration *fa = sa->isFuncAliasDeclaration()) - { - FuncDeclaration *f = fa->toAliasFunc(); - if (!fa->hasOverloads && f->isUnique()) - { - // Strip FuncAlias only when the aliased function - // does not have any overloads. - sa = f; - } - } - (*tiargs)[j] = sa; - - TemplateDeclaration *td = sa->isTemplateDeclaration(); - if (td && td->semanticRun == PASSinit && td->literal) - { - dsymbolSemantic(td, sc); - } - FuncDeclaration *fd = sa->isFuncDeclaration(); - if (fd) - fd->functionSemantic(); - } - else if (isParameter(o)) - { - } - else - { - assert(0); - } - //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); - } - return !err; -} - -bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs) -{ - if (havetempdecl) - { - TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration(); - assert(tempdecl); - assert(tempdecl->_scope); - // Deduce tdtypes - tdtypes.setDim(tempdecl->parameters->length); - if (!tempdecl->matchWithInstance(sc, this, &tdtypes, fargs, 2)) - { - error("incompatible arguments for template instantiation"); - return false; - } - // TODO: Normalizing tiargs for bugzilla 7469 is necessary? - return true; - } - - unsigned errs = global.errors; - TemplateDeclaration *td_last = NULL; - - struct ParamBest - { - // context - Scope *sc; - TemplateInstance *ti; - Objects dedtypes; - // result - TemplateDeclaration *td_best; - TemplateDeclaration *td_ambig; - MATCH m_best; - - static int fp(void *param, Dsymbol *s) - { - return ((ParamBest *)param)->fp(s); - } - int fp(Dsymbol *s) - { - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (!td) - return 0; - if (td->inuse) - { - td->error(ti->loc, "recursive template expansion"); - return 1; - } - if (td == td_best) // skip duplicates - return 0; - - //printf("td = %s\n", td->toPrettyChars()); - - // If more arguments than parameters, - // then this is no match. - if (td->parameters->length < ti->tiargs->length) - { - if (!td->isVariadic()) - return 0; - } - - dedtypes.setDim(td->parameters->length); - dedtypes.zero(); - assert(td->semanticRun != PASSinit); - MATCH m = td->matchWithInstance(sc, ti, &dedtypes, ti->fargs, 0); - //printf("matchWithInstance = %d\n", m); - if (m <= MATCHnomatch) // no match at all - return 0; - - if (m < m_best) goto Ltd_best; - if (m > m_best) goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(sc, td_best, ti->fargs); - MATCH c2 = td_best->leastAsSpecialized(sc, td, ti->fargs); - //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto Ltd; - if (c1 < c2) goto Ltd_best; - } - - td_ambig = td; - return 0; - - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - return 0; - - Ltd: // td is the new best match - td_ambig = NULL; - td_best = td; - m_best = m; - ti->tdtypes.setDim(dedtypes.length); - memcpy(ti->tdtypes.tdata(), dedtypes.tdata(), ti->tdtypes.length * sizeof(void *)); - return 0; - } - }; - ParamBest p; - // context - p.ti = this; - p.sc = sc; - - /* Since there can be multiple TemplateDeclaration's with the same - * name, look for the best match. - */ - OverloadSet *tovers = tempdecl->isOverloadSet(); - size_t overs_dim = tovers ? tovers->a.length : 1; - for (size_t oi = 0; oi < overs_dim; oi++) - { - // result - p.td_best = NULL; - p.td_ambig = NULL; - p.m_best = MATCHnomatch; - - Dsymbol *dstart = tovers ? tovers->a[oi] : tempdecl; - overloadApply(dstart, &p, &ParamBest::fp); - - if (p.td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration:\n%s: %s\nand\n%s: %s", - p.td_best->kind(), p.td_best->parent->toPrettyChars(), p.td_best->ident->toChars(), - p.td_best->loc.toChars() , p.td_best->toChars(), - p.td_ambig->loc.toChars(), p.td_ambig->toChars()); - return false; - } - if (p.td_best) - { - if (!td_last) - td_last = p.td_best; - else if (td_last != p.td_best) - { - ScopeDsymbol::multiplyDefined(loc, td_last, p.td_best); - return false; - } - } - } - - if (td_last) - { - /* Bugzilla 7469: Normalize tiargs by using corresponding deduced - * template value parameters and tuples for the correct mangling. - * - * By doing this before hasNestedArgs, CTFEable local variable will be - * accepted as a value parameter. For example: - * - * void foo() { - * struct S(int n) {} // non-global template - * const int num = 1; // CTFEable local variable - * S!num s; // S!1 is instantiated, not S!num - * } - */ - size_t dim = td_last->parameters->length - (td_last->isVariadic() ? 1 : 0); - for (size_t i = 0; i < dim; i++) - { - if (tiargs->length <= i) - tiargs->push(tdtypes[i]); - assert(i < tiargs->length); - - TemplateValueParameter *tvp = (*td_last->parameters)[i]->isTemplateValueParameter(); - if (!tvp) - continue; - assert(tdtypes[i]); - // tdtypes[i] is already normalized to the required type in matchArg - - (*tiargs)[i] = tdtypes[i]; - } - if (td_last->isVariadic() && tiargs->length == dim && tdtypes[dim]) - { - Tuple *va = isTuple(tdtypes[dim]); - assert(va); - for (size_t i = 0; i < va->objects.length; i++) - tiargs->push(va->objects[i]); - } - } - else if (errors && inst) - { - // instantiation was failed with error reporting - assert(global.errors); - return false; - } - else - { - TemplateDeclaration *tdecl = tempdecl->isTemplateDeclaration(); - - if (errs != global.errors) - errorSupplemental(loc, "while looking for match for %s", toChars()); - else if (tdecl && !tdecl->overnext) - { - // Only one template, so we can give better error message - error("does not match template declaration %s", tdecl->toChars()); - } - else - ::error(loc, "%s %s.%s does not match any template declaration", - tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars()); - return false; - } - - /* The best match is td_last - */ - tempdecl = td_last; - - return (errs == global.errors); -} - -/***************************************************** - * Determine if template instance is really a template function, - * and that template function needs to infer types from the function - * arguments. - * - * Like findBestMatch, iterate possible template candidates, - * but just looks only the necessity of type inference. - */ - -bool TemplateInstance::needsTypeInference(Scope *sc, int flag) -{ - //printf("TemplateInstance::needsTypeInference() %s\n", toChars()); - if (semanticRun != PASSinit) - return false; - - struct ParamNeedsInf - { - // context - Scope *sc; - TemplateInstance *ti; - int flag; - // result - Objects dedtypes; - size_t count; - - static int fp(void *param, Dsymbol *s) - { - return ((ParamNeedsInf *)param)->fp(s); - } - int fp(Dsymbol *s) - { - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (!td) - return 0; - if (td->inuse) - { - td->error(ti->loc, "recursive template expansion"); - return 1; - } - - /* If any of the overloaded template declarations need inference, - * then return true - */ - FuncDeclaration *fd; - if (!td->onemember) - return 0; - if (TemplateDeclaration *td2 = td->onemember->isTemplateDeclaration()) - { - if (!td2->onemember || !td2->onemember->isFuncDeclaration()) - return 0; - if (ti->tiargs->length >= td->parameters->length - (td->isVariadic() ? 1 : 0)) - return 0; - return 1; - } - if ((fd = td->onemember->isFuncDeclaration()) == NULL || - fd->type->ty != Tfunction) - { - return 0; - } - - for (size_t i = 0; i < td->parameters->length; i++) - { - if ((*td->parameters)[i]->isTemplateThisParameter()) - return 1; - } - - /* Determine if the instance arguments, tiargs, are all that is necessary - * to instantiate the template. - */ - //printf("tp = %p, td->parameters->length = %d, tiargs->length = %d\n", tp, td->parameters->length, ti->tiargs->length); - TypeFunction *tf = (TypeFunction *)fd->type; - if (size_t dim = tf->parameterList.length()) - { - TemplateParameter *tp = td->isVariadic(); - if (tp && td->parameters->length > 1) - return 1; - - if (!tp && ti->tiargs->length < td->parameters->length) - { - // Can remain tiargs be filled by default arguments? - for (size_t i = ti->tiargs->length; i < td->parameters->length; i++) - { - if (!(*td->parameters)[i]->hasDefaultArg()) - return 1; - } - } - - for (size_t i = 0; i < dim; i++) - { - // 'auto ref' needs inference. - if (tf->parameterList[i]->storageClass & STCauto) - return 1; - } - } - - if (!flag) - { - /* Calculate the need for overload resolution. - * When only one template can match with tiargs, inference is not necessary. - */ - dedtypes.setDim(td->parameters->length); - dedtypes.zero(); - if (td->semanticRun == PASSinit) - { - if (td->_scope) - { - // Try to fix forward reference. Ungag errors while doing so. - Ungag ungag = td->ungagSpeculative(); - dsymbolSemantic(td, td->_scope); - } - if (td->semanticRun == PASSinit) - { - ti->error("%s forward references template declaration %s", ti->toChars(), td->toChars()); - return 1; - } - } - assert(td->semanticRun != PASSinit); - MATCH m = td->matchWithInstance(sc, ti, &dedtypes, NULL, 0); - if (m <= MATCHnomatch) - return 0; - } - - /* If there is more than one function template which matches, we may - * need type inference (see Bugzilla 4430) - */ - if (++count > 1) - return 1; - - return 0; - } - }; - ParamNeedsInf p; - // context - p.ti = this; - p.sc = sc; - p.flag = flag; - // result - p.count = 0; - - OverloadSet *tovers = tempdecl->isOverloadSet(); - size_t overs_dim = tovers ? tovers->a.length : 1; - unsigned olderrs = global.errors; - for (size_t oi = 0; oi < overs_dim; oi++) - { - if (overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamNeedsInf::fp)) - return true; - } - if (olderrs != global.errors) - { - if (!global.gag) - { - errorSupplemental(loc, "while looking for match for %s", toChars()); - semanticRun = PASSsemanticdone; - inst = this; - } - errors = true; - } - //printf("false\n"); - return false; -} - - -/***************************************** - * Determines if a TemplateInstance will need a nested - * generation of the TemplateDeclaration. - * Sets enclosing property if so, and returns != 0; - */ - -bool TemplateInstance::hasNestedArgs(Objects *args, bool isstatic) -{ - int nested = 0; - //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl->ident->toChars()); - - /* A nested instance happens when an argument references a local - * symbol that is on the stack. - */ - for (size_t i = 0; i < args->length; i++) - { - RootObject *o = (*args)[i]; - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - if (ea) - { - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKthis) - { - sa = ((ThisExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKfunction) - { - if (((FuncExp *)ea)->td) - sa = ((FuncExp *)ea)->td; - else - sa = ((FuncExp *)ea)->fd; - goto Lsa; - } - // Emulate Expression::toMangleBuffer call that had exist in TemplateInstance::genIdent. - if (ea->op != TOKint64 && - ea->op != TOKfloat64 && - ea->op != TOKcomplex80 && - ea->op != TOKnull && - ea->op != TOKstring && - ea->op != TOKarrayliteral && - ea->op != TOKassocarrayliteral && - ea->op != TOKstructliteral) - { - ea->error("expression %s is not a valid template value argument", ea->toChars()); - errors = true; - } - } - else if (sa) - { - Lsa: - sa = sa->toAlias(); - TemplateDeclaration *td = sa->isTemplateDeclaration(); - if (td) - { - TemplateInstance *ti = sa->toParent()->isTemplateInstance(); - if (ti && ti->enclosing) - sa = ti; - } - TemplateInstance *ti = sa->isTemplateInstance(); - Declaration *d = sa->isDeclaration(); - if ((td && td->literal) || - (ti && ti->enclosing) || - (d && !d->isDataseg() && - !(d->storage_class & STCmanifest) && - (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && - !isTemplateMixin() - )) - { - // if module level template - if (isstatic) - { - Dsymbol *dparent = sa->toParent2(); - if (!enclosing) - enclosing = dparent; - else if (enclosing != dparent) - { - /* Select the more deeply nested of the two. - * Error if one is not nested inside the other. - */ - for (Dsymbol *p = enclosing; p; p = p->parent) - { - if (p == dparent) - goto L1; // enclosing is most nested - } - for (Dsymbol *p = dparent; p; p = p->parent) - { - if (p == enclosing) - { - enclosing = dparent; - goto L1; // dparent is most nested - } - } - error("%s is nested in both %s and %s", - toChars(), enclosing->toChars(), dparent->toChars()); - errors = true; - } - L1: - //printf("\tnested inside %s\n", enclosing->toChars()); - nested |= 1; - } - else - { - error("cannot use local `%s` as parameter to non-global template %s", sa->toChars(), tempdecl->toChars()); - errors = true; - } - } - } - else if (va) - { - nested |= (int)hasNestedArgs(&va->objects, isstatic); - } - } - //printf("-TemplateInstance::hasNestedArgs('%s') = %d\n", tempdecl->ident->toChars(), nested); - return nested != 0; -} - -/***************************************** - * Append 'this' to the specific module members[] - */ -Dsymbols *TemplateInstance::appendToModuleMember() -{ - Module *mi = minst; // instantiated -> inserted module - - if (global.params.useUnitTests) - { - // Turn all non-root instances to speculative - if (mi && !mi->isRoot()) - mi = NULL; - } - - //printf("%s->appendToModuleMember() enclosing = %s mi = %s\n", - // toPrettyChars(), - // enclosing ? enclosing->toPrettyChars() : NULL, - // mi ? mi->toPrettyChars() : NULL); - if (!mi || mi->isRoot()) - { - /* If the instantiated module is speculative or root, insert to the - * member of a root module. Then: - * - semantic3 pass will get called on the instance members. - * - codegen pass will get a selection chance to do/skip it. - */ - - struct N - { - static Dsymbol *getStrictEnclosing(TemplateInstance *ti) - { - do - { - if (ti->enclosing) - return ti->enclosing; - ti = ti->tempdecl->isInstantiated(); - } - while (ti); - return NULL; - } - }; - Dsymbol *enc = N::getStrictEnclosing(this); - - // insert target is made stable by using the module - // where tempdecl is declared. - mi = (enc ? enc : tempdecl)->getModule(); - if (!mi->isRoot()) - mi = mi->importedFrom; - assert(mi->isRoot()); - } - else - { - /* If the instantiated module is non-root, insert to the member of the - * non-root module. Then: - * - semantic3 pass won't be called on the instance. - * - codegen pass won't reach to the instance. - */ - } - //printf("\t--> mi = %s\n", mi->toPrettyChars()); - - if (memberOf == mi) // already a member - { - return NULL; - } - - Dsymbols *a = mi->members; - a->push(this); - memberOf = mi; - if (mi->semanticRun >= PASSsemantic2done && mi->isRoot()) - Module::addDeferredSemantic2(this); - if (mi->semanticRun >= PASSsemantic3done && mi->isRoot()) - Module::addDeferredSemantic3(this); - return a; -} - -/**************************************** - * This instance needs an identifier for name mangling purposes. - * Create one by taking the template declaration name and adding - * the type signature for it. - */ - -Identifier *TemplateInstance::genIdent(Objects *args) -{ - //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); - assert(args == tiargs); - OutBuffer buf; - mangleToBuffer(this, &buf); - //printf("\tgenIdent = %s\n", id); - return Identifier::idPool(buf.peekChars()); -} - -/************************************* - * Lazily generate identifier for template instance. - * This is because 75% of the ident's are never needed. - */ - -Identifier *TemplateInstance::getIdent() -{ - if (!ident && inst && !errors) - ident = genIdent(tiargs); // need an identifier for name mangling purposes. - return ident; -} - -/**************************************************** - * Declare parameters of template instance, initialize them with the - * template instance arguments. - */ - -void TemplateInstance::declareParameters(Scope *sc) -{ - TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration(); - assert(tempdecl); - - //printf("TemplateInstance::declareParameters()\n"); - for (size_t i = 0; i < tdtypes.length; i++) - { - TemplateParameter *tp = (*tempdecl->parameters)[i]; - //RootObject *o = (*tiargs)[i]; - RootObject *o = tdtypes[i]; // initializer for tp - - //printf("\ttdtypes[%d] = %p\n", i, o); - tempdecl->declareParameter(sc, tp, o); - } -} - -/************************************** - * Given an error instantiating the TemplateInstance, - * give the nested TemplateInstance instantiations that got - * us here. Those are a list threaded into the nested scopes. - */ -void TemplateInstance::printInstantiationTrace() -{ - if (global.gag) - return; - - const unsigned max_shown = 6; - const char format[] = "instantiated from here: %s"; - - // determine instantiation depth and number of recursive instantiations - unsigned n_instantiations = 1; - unsigned n_totalrecursions = 0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - ++n_instantiations; - // If two instantiations use the same declaration, they are recursive. - // (this works even if they are instantiated from different places in the - // same template). - // In principle, we could also check for multiple-template recursion, but it's - // probably not worthwhile. - if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl - && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) - ++n_totalrecursions; - } - - // show full trace only if it's short or verbose is on - if (n_instantiations <= max_shown || global.params.verbose) - { - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - cur->errors = true; - errorSupplemental(cur->loc, format, cur->toChars()); - } - } - else if (n_instantiations - n_totalrecursions <= max_shown) - { - // By collapsing recursive instantiations into a single line, - // we can stay under the limit. - int recursionDepth=0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - cur->errors = true; - if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl - && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) - { - ++recursionDepth; - } - else - { - if (recursionDepth) - errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars()); - else - errorSupplemental(cur->loc, format, cur->toChars()); - recursionDepth = 0; - } - } - } - else - { - // Even after collapsing the recursions, the depth is too deep. - // Just display the first few and last few instantiations. - unsigned i = 0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - cur->errors = true; - - if (i == max_shown / 2) - errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown); - - if (i < max_shown / 2 || - i >= n_instantiations - max_shown + max_shown / 2) - errorSupplemental(cur->loc, format, cur->toChars()); - ++i; - } - } -} - -Dsymbol *TemplateInstance::toAlias() -{ - if (!inst) - { - // Maybe we can resolve it - if (_scope) - { - dsymbolSemantic(this, _scope); - } - if (!inst) - { - error("cannot resolve forward reference"); - errors = true; - return this; - } - } - - if (inst != this) - return inst->toAlias(); - - if (aliasdecl) - { - return aliasdecl->toAlias(); - } - - return inst; -} - -const char *TemplateInstance::kind() const -{ - return "template instance"; -} - -bool TemplateInstance::oneMember(Dsymbol **ps, Identifier *) -{ - *ps = NULL; - return true; -} - -const char *TemplateInstance::toChars() -{ - OutBuffer buf; - toCBufferInstance(this, &buf); - return buf.extractChars(); -} - -const char *TemplateInstance::toPrettyCharsHelper() -{ - OutBuffer buf; - toCBufferInstance(this, &buf, true); - return buf.extractChars(); -} - -/************************************* - * Compare proposed template instantiation with existing template instantiation. - * Note that this is not commutative because of the auto ref check. - * Params: - * this = proposed template instantiation - * o = existing template instantiation - * Returns: - * 0 for match, 1 for no match - */ -int TemplateInstance::compare(RootObject *o) -{ - TemplateInstance *ti = (TemplateInstance *)o; - - //printf("this = %p, ti = %p\n", this, ti); - assert(tdtypes.length == ti->tdtypes.length); - - // Nesting must match - if (enclosing != ti->enclosing) - { - //printf("test2 enclosing %s ti->enclosing %s\n", enclosing ? enclosing->toChars() : "", ti->enclosing ? ti->enclosing->toChars() : ""); - goto Lnotequals; - } - //printf("parent = %s, ti->parent = %s\n", parent->toPrettyChars(), ti->parent->toPrettyChars()); - - if (!arrayObjectMatch(&tdtypes, &ti->tdtypes)) - goto Lnotequals; - - /* Template functions may have different instantiations based on - * "auto ref" parameters. - */ - if (FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration()) - { - if (!fd->errors) - { - ParameterList fparameters = fd->getParameterList(); - size_t nfparams = fparameters.length(); // Num function parameters - for (size_t j = 0; j < nfparams; j++) - { - Parameter *fparam = fparameters[j]; - if (fparam->storageClass & STCautoref) // if "auto ref" - { - if (!fargs) - goto Lnotequals; - if (fargs->length <= j) - break; - Expression *farg = (*fargs)[j]; - if (farg->isLvalue()) - { - if (!(fparam->storageClass & STCref)) - goto Lnotequals; // auto ref's don't match - } - else - { - if (fparam->storageClass & STCref) - goto Lnotequals; // auto ref's don't match - } - } - } - } - } - return 0; - - Lnotequals: - return 1; -} - -hash_t TemplateInstance::toHash() -{ - if (!hash) - { - hash = (size_t)(void *)enclosing; - hash += arrayObjectHash(&tdtypes); - hash += hash == 0; - } - return hash; -} - -/************************************** - * IsExpression can evaluate the specified type speculatively, and even if - * it instantiates any symbols, they are normally unnecessary for the - * final executable. - * However, if those symbols leak to the actual code, compiler should remark - * them as non-speculative to generate their code and link to the final executable. - */ -void unSpeculative(Scope *sc, RootObject *o) -{ - if (!o) - return; - - if (Tuple *tup = isTuple(o)) - { - for (size_t i = 0; i < tup->objects.length; i++) - { - unSpeculative(sc, tup->objects[i]); - } - return; - } - - Dsymbol *s = getDsymbol(o); - if (!s) - return; - - if (Declaration *d = s->isDeclaration()) - { - if (VarDeclaration *vd = d->isVarDeclaration()) - o = vd->type; - else if (AliasDeclaration *ad = d->isAliasDeclaration()) - { - o = ad->getType(); - if (!o) - o = ad->toAlias(); - } - else - o = d->toAlias(); - - s = getDsymbol(o); - if (!s) - return; - } - - if (TemplateInstance *ti = s->isTemplateInstance()) - { - // If the instance is already non-speculative, - // or it is leaked to the speculative scope. - if (ti->minst != NULL || sc->minst == NULL) - return; - - // Remark as non-speculative instance. - ti->minst = sc->minst; - if (!ti->tinst) - ti->tinst = sc->tinst; - - unSpeculative(sc, ti->tempdecl); - } - - if (TemplateInstance *ti = s->isInstantiated()) - unSpeculative(sc, ti); -} - -/** - Returns: true if the instances' innards are discardable. - - The idea of this function is to see if the template instantiation - can be 100% replaced with its eponymous member. All other members - can be discarded, even in the compiler to free memory (for example, - the template could be expanded in a region allocator, deemed trivial, - the end result copied back out independently and the entire region freed), - and can be elided entirely from the binary. - - The current implementation affects code that generally looks like: - - --- - template foo(args...) { - some_basic_type_or_string helper() { .... } - enum foo = helper(); - } - --- - - since it was the easiest starting point of implementation but it can and - should be expanded more later. -*/ -static bool isDiscardable(TemplateInstance *ti) -{ - if (ti->aliasdecl == NULL) - return false; - - VarDeclaration *v = ti->aliasdecl->isVarDeclaration(); - if (v == NULL) - return false; - - if (!(v->storage_class & STCmanifest)) - return false; - - // Currently only doing basic types here because it is the easiest proof-of-concept - // implementation with minimal risk of side effects, but it could likely be - // expanded to any type that already exists outside this particular instance. - if (!(v->type->equals(Type::tstring) || (v->type->isTypeBasic() != NULL))) - return false; - - // Static ctors and dtors, even in an eponymous enum template, are still run, - // so if any of them are in here, we'd better not assume it is trivial lest - // we break useful code - for (size_t i = 0; i < ti->members->length; i++) - { - Dsymbol *member = (*ti->members)[i]; - if (member->hasStaticCtorOrDtor()) - return false; - if (member->isStaticDtorDeclaration()) - return false; - if (member->isStaticCtorDeclaration()) - return false; - } - - // but if it passes through this gauntlet... it should be fine. D code will - // see only the eponymous member, outside stuff can never access it, even through - // reflection; the outside world ought to be none the wiser. Even dmd should be - // able to simply free the memory of everything except the final result. - - return true; -} - -/*********************************************** - * Returns true if this is not instantiated in non-root module, and - * is a part of non-speculative instantiatiation. - * - * Note: minst does not stabilize until semantic analysis is completed, - * so don't call this function during semantic analysis to return precise result. - */ -bool TemplateInstance::needsCodegen() -{ - if (!minst) - { - // If this is a speculative instantiation, - // 1. do codegen if ancestors really needs codegen. - // 2. become non-speculative if siblings are not speculative - - TemplateInstance *tnext = this->tnext; - TemplateInstance *tinst = this->tinst; - // At first, disconnect chain first to prevent infinite recursion. - this->tnext = NULL; - this->tinst = NULL; - - // Determine necessity of tinst before tnext. - if (tinst && tinst->needsCodegen()) - { - minst = tinst->minst; // cache result - if (global.params.allInst && minst) - { - return true; - } - assert(minst); - assert(minst->isRoot() || minst->rootImports()); - return true; - } - if (tnext && (tnext->needsCodegen() || tnext->minst)) - { - minst = tnext->minst; // cache result - if (global.params.allInst && minst) - { - return true; - } - assert(minst); - return minst->isRoot() || minst->rootImports(); - } - - // Elide codegen because this is really speculative. - return false; - } - - if (global.params.allInst) - { - return true; - } - - if (isDiscardable(this)) - { - return false; - } - - /* Even when this is reached to the codegen pass, - * a non-root nested template should not generate code, - * due to avoid ODR violation. - */ - if (enclosing && enclosing->inNonRoot()) - { - if (tinst) - { - bool r = tinst->needsCodegen(); - minst = tinst->minst; // cache result - return r; - } - if (tnext) - { - bool r = tnext->needsCodegen(); - minst = tnext->minst; // cache result - return r; - } - return false; - } - - if (global.params.useUnitTests) - { - // Prefer instantiations from root modules, to maximize link-ability. - if (minst->isRoot()) - return true; - - TemplateInstance *tnext = this->tnext; - TemplateInstance *tinst = this->tinst; - this->tnext = NULL; - this->tinst = NULL; - - if (tinst && tinst->needsCodegen()) - { - minst = tinst->minst; // cache result - assert(minst); - assert(minst->isRoot() || minst->rootImports()); - return true; - } - if (tnext && tnext->needsCodegen()) - { - minst = tnext->minst; // cache result - assert(minst); - assert(minst->isRoot() || minst->rootImports()); - return true; - } - - // Bugzilla 2500 case - if (minst->rootImports()) - return true; - - // Elide codegen because this is not included in root instances. - return false; - } - else - { - // Prefer instantiations from non-root module, to minimize object code size. - - /* If a TemplateInstance is ever instantiated by non-root modules, - * we do not have to generate code for it, - * because it will be generated when the non-root module is compiled. - * - * But, if the non-root 'minst' imports any root modules, it might still need codegen. - * - * The problem is if A imports B, and B imports A, and both A - * and B instantiate the same template, does the compilation of A - * or the compilation of B do the actual instantiation? - * - * See Bugzilla 2500. - */ - if (!minst->isRoot() && !minst->rootImports()) - return false; - - TemplateInstance *tnext = this->tnext; - this->tnext = NULL; - - if (tnext && !tnext->needsCodegen() && tnext->minst) - { - minst = tnext->minst; // cache result - assert(!minst->isRoot()); - return false; - } - - // Do codegen because this is not included in non-root instances. - return true; - } -} - -/* ======================== TemplateMixin ================================ */ - -TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs) - : TemplateInstance(loc, tqual->idents.length ? (Identifier *)tqual->idents[tqual->idents.length - 1] - : ((TypeIdentifier *)tqual)->ident) -{ - //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); - this->ident = ident; - this->tqual = tqual; - this->tiargs = tiargs ? tiargs : new Objects(); -} - -Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *) -{ - TemplateMixin *tm = new TemplateMixin(loc, ident, - (TypeQualified *)tqual->syntaxCopy(), tiargs); - return TemplateInstance::syntaxCopy(tm); -} - -bool TemplateMixin::findTempDecl(Scope *sc) -{ - // Follow qualifications to find the TemplateDeclaration - if (!tempdecl) - { - Expression *e; - Type *t; - Dsymbol *s; - tqual->resolve(loc, sc, &e, &t, &s); - if (!s) - { - error("is not defined"); - return false; - } - s = s->toAlias(); - tempdecl = s->isTemplateDeclaration(); - OverloadSet *os = s->isOverloadSet(); - - /* If an OverloadSet, look for a unique member that is a template declaration - */ - if (os) - { - Dsymbol *ds = NULL; - for (size_t i = 0; i < os->a.length; i++) - { - Dsymbol *s2 = os->a[i]->isTemplateDeclaration(); - if (s2) - { - if (ds) - { - tempdecl = os; - break; - } - ds = s2; - } - } - } - if (!tempdecl) - { - error("%s isn't a template", s->toChars()); - return false; - } - } - assert(tempdecl); - - struct ParamFwdResTm - { - static int fp(void *param, Dsymbol *s) - { - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (!td) - return 0; - - TemplateMixin *tm = (TemplateMixin *)param; - if (td->semanticRun == PASSinit) - { - if (td->_scope) - dsymbolSemantic(td, td->_scope); - else - { - tm->semanticRun = PASSinit; - return 1; - } - } - return 0; - } - }; - // Look for forward references - OverloadSet *tovers = tempdecl->isOverloadSet(); - size_t overs_dim = tovers ? tovers->a.length : 1; - for (size_t oi = 0; oi < overs_dim; oi++) - { - if (overloadApply(tovers ? tovers->a[oi] : tempdecl, (void *)this, &ParamFwdResTm::fp)) - return false; - } - return true; -} - -const char *TemplateMixin::kind() const -{ - return "mixin"; -} - -bool TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident) -{ - return Dsymbol::oneMember(ps, ident); -} - -int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param) -{ - if (_scope) // if fwd reference - dsymbolSemantic(this, NULL); // try to resolve it - if (members) - { - for (size_t i = 0; i < members->length; i++) - { - Dsymbol *s = (*members)[i]; - if (s) - { - if (s->apply(fp, param)) - return 1; - } - } - } - return 0; -} - -bool TemplateMixin::hasPointers() -{ - //printf("TemplateMixin::hasPointers() %s\n", toChars()); - - if (members) - { - for (size_t i = 0; i < members->length; i++) - { - Dsymbol *s = (*members)[i]; - //printf(" s = %s %s\n", s->kind(), s->toChars()); - if (s->hasPointers()) - { - return true; - } - } - } - return false; -} - -void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - //printf("TemplateMixin::setFieldOffset() %s\n", toChars()); - if (_scope) // if fwd reference - dsymbolSemantic(this, NULL); // try to resolve it - if (members) - { - for (size_t i = 0; i < members->length; i++) - { - Dsymbol *s = (*members)[i]; - //printf("\t%s\n", s->toChars()); - s->setFieldOffset(ad, poffset, isunion); - } - } -} - -const char *TemplateMixin::toChars() -{ - OutBuffer buf; - toCBufferInstance(this, &buf); - return buf.extractChars(); -} |