summaryrefslogtreecommitdiff
path: root/gcc/d/dmd/dtemplate.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/dtemplate.c')
-rw-r--r--gcc/d/dmd/dtemplate.c7581
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 = &pr; // 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 = &pr; // 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();
-}