diff --git a/src/template.c b/src/template.c index 8d6287b526bb..d81c093305ab 100644 --- a/src/template.c +++ b/src/template.c @@ -582,6 +582,42 @@ void TemplateDeclaration::semantic(Scope *sc) } } + /* Calculate TemplateParameter::dependent + */ + TemplateParameters tparams; + tparams.setDim(1); + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (*parameters)[i]; + tparams[0] = tp; + + for (size_t j = 0; j < parameters->dim; j++) + { + // Skip cases like: X(T : T) + if (i == j) + continue; + + if (TemplateTypeParameter *ttp = (*parameters)[j]->isTemplateTypeParameter()) + { + Type *t = ttp->specType; + if (t && t->reliesOnTident(&tparams)) + tp->dependent = true; + } + else if (TemplateAliasParameter *tap = (*parameters)[j]->isTemplateAliasParameter()) + { + Type *t = tap->specType; + if (t && t->reliesOnTident(&tparams)) + tp->dependent = true; + else if (tap->specAlias) + { + t = isType(tap->specAlias); + if (t && t->reliesOnTident(&tparams)) + tp->dependent = true; + } + } + } + } + paramscope->pop(); // Compute again @@ -4196,6 +4232,7 @@ TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) { this->loc = loc; this->ident = ident; + this->dependent = false; this->sparam = NULL; } @@ -4366,7 +4403,8 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, RootObject *oarg, //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"); + { + //printf("\tfailed deduceType\n"); goto Lnomatch; } @@ -4378,11 +4416,13 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, RootObject *oarg, else { if ((*dedtypes)[i]) - { // Must match already deduced type + { + // Must match already deduced type Type *t = (Type *)(*dedtypes)[i]; if (!t->equals(ta)) - { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); + { + //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); goto Lnomatch; } } @@ -4397,7 +4437,7 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, RootObject *oarg, if (psparam) *psparam = new AliasDeclaration(loc, ident, ta); //printf("\tm = %d\n", m); - return m; + return dependent ? MATCHexact : m; Lnomatch: if (psparam) @@ -4443,10 +4483,8 @@ void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) void *TemplateTypeParameter::dummyArg() { - Type *t; - if (specType) - t = specType; - else + Type *t = specType; + if (!t) { // Use this for alias-parameter's too (?) if (!tdummy) @@ -4605,6 +4643,7 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg, Declaration **psparam) { //printf("TemplateAliasParameter::matchArg()\n"); + MATCH m = MATCHexact; RootObject *sa = getDsymbol(oarg); Expression *ea = isExpression(oarg); if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) @@ -4613,11 +4652,15 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg, 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(); + { + Declaration *d = ((Dsymbol *)sa)->isDeclaration(); if (!d) goto Lnomatch; if (!d->type->equals(specType)) @@ -4628,12 +4671,18 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg, { sa = oarg; if (ea) - { if (specType) + { + if (specType) { if (!ea->type->equals(specType)) goto Lnomatch; } } + else if (sa && sa == TemplateTypeParameter::tdummy) + { + // Bugzilla 2025: Aggregate Types should preferentially + // match to the template type parameter. + } else goto Lnomatch; } @@ -4642,22 +4691,29 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg, { if (sa == sdummy) goto Lnomatch; - if (sa != specAlias && isDsymbol(sa)) + Dsymbol *sx = isDsymbol(sa); + if (sa != specAlias && sx) { - TemplateInstance *ti = isDsymbol(sa)->isTemplateInstance(); Type *ta = isType(specAlias); - if (!ti || !ta) + if (!ta) + goto Lnomatch; + + TemplateInstance *ti = sx->isTemplateInstance(); + if (!ti && sx->parent) + ti = sx->parent->isTemplateInstance(); + if (!ti) goto Lnomatch; + Type *t = new TypeInstance(Loc(), ti); - MATCH m = deduceType(t, sc, ta, parameters, dedtypes); - if (m <= MATCHnomatch) + MATCH m2 = deduceType(t, sc, ta, parameters, dedtypes); + if (m2 <= MATCHnomatch) goto Lnomatch; } } else if ((*dedtypes)[i]) - { // Must match already deduced symbol + { + // Must match already deduced symbol RootObject *si = (*dedtypes)[i]; - if (!sa || si != sa) goto Lnomatch; } @@ -4669,6 +4725,10 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg, { *psparam = new AliasDeclaration(loc, ident, s); } + else if (Type *t = isType(sa)) + { + *psparam = new AliasDeclaration(loc, ident, t); + } else { assert(ea); @@ -4681,7 +4741,7 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg, *psparam = v; } } - return MATCHexact; + return dependent ? MATCHexact : m; Lnomatch: if (psparam) @@ -4724,9 +4784,8 @@ void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) void *TemplateAliasParameter::dummyArg() -{ RootObject *s; - - s = specAlias; +{ + RootObject *s = specAlias; if (!s) { if (!sdummy) @@ -4967,7 +5026,7 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, RootObject *oarg, sparam->storage_class = STCmanifest; *psparam = sparam; } - return m; + return dependent ? MATCHexact : m; Lnomatch: //printf("\tno match\n"); @@ -5006,9 +5065,8 @@ void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) void *TemplateValueParameter::dummyArg() -{ Expression *e; - - e = specValue; +{ + Expression *e = specValue; if (!e) { // Create a dummy value @@ -5130,7 +5188,7 @@ MATCH TemplateTupleParameter::matchArg(Scope *sc, RootObject *oarg, if (psparam) *psparam = new TupleDeclaration(loc, ident, &ovar->objects); - return MATCHexact; + return dependent ? MATCHexact : MATCHconvert; } diff --git a/src/template.h b/src/template.h index 2beb47455ee1..0a41a1ee5337 100644 --- a/src/template.h +++ b/src/template.h @@ -133,6 +133,16 @@ class TemplateParameter Loc loc; Identifier *ident; + /* True if this is a part of precedent parameter specialization pattern. + * + * template A(T : X!TL, alias X, TL...) {} + * // X and TL are dependent template parameter + * + * A dependent template parameter should return MATCHexact in matchArg() + * to respect the match level of the corresponding precedent parameter. + */ + bool dependent; + Declaration *sparam; TemplateParameter(Loc loc, Identifier *ident); diff --git a/test/runnable/template9.d b/test/runnable/template9.d index d03070979f20..5d63dd5f6950 100644 --- a/test/runnable/template9.d +++ b/test/runnable/template9.d @@ -203,6 +203,47 @@ void test1780() static assert(is(SQ1780 == Tuple1780!(bool, short))); } +/**********************************/ +// 1659 + +class Foo1659 { } +class Bar1659 : Foo1659 { } + +void f1659(T : Foo1659)() { } +void f1659(alias T)() { static assert(false); } + +void test1659() +{ + f1659!Bar1659(); +} + +/**********************************/ +// 2025 + +struct S2025 {} +void f2025() {} + +template Foo2025(int i) { enum Foo2025 = 1; } +template Foo2025(TL...) { enum Foo2025 = 2; } +static assert(Foo2025!1 == 1); +static assert(Foo2025!int == 2); +static assert(Foo2025!S2025 == 2); +static assert(Foo2025!f2025 == 2); + +template Bar2025(T) { enum Bar2025 = 1; } +template Bar2025(A...) { enum Bar2025 = 2; } +static assert(Bar2025!1 == 2); +static assert(Bar2025!int == 1); // 2 -> 1 +static assert(Bar2025!S2025 == 1); // 2 -> 1 +static assert(Bar2025!f2025 == 2); + +template Baz2025(T) { enum Baz2025 = 1; } +template Baz2025(alias A) { enum Baz2025 = 2; } +static assert(Baz2025!1 == 2); +static assert(Baz2025!int == 1); +static assert(Baz2025!S2025 == 1); // 2 -> 1 +static assert(Baz2025!f2025 == 2); + /**********************************/ // 3608 @@ -3043,6 +3084,18 @@ void test11843() static assert(!is(typeof(bar3) == typeof(bar4))); } +/******************************************/ +// 12077 + +struct S12077(A) {} + +alias T12077(alias T : Base!Args, alias Base, Args...) = Base; +static assert(__traits(isSame, T12077!(S12077!int), S12077)); + +alias U12077(alias T : Base!Args, alias Base, Args...) = Base; +alias U12077( T : Base!Args, alias Base, Args...) = Base; +static assert(__traits(isSame, U12077!(S12077!int), S12077)); + /******************************************/ // 12122