Showing with 90 additions and 12 deletions.
  1. +28 −7 src/dtemplate.d
  2. +17 −2 src/expression.d
  3. +15 −3 src/mtype.d
  4. +30 −0 test/runnable/template9.d
35 changes: 28 additions & 7 deletions src/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -4811,7 +4811,8 @@ public:

extern (C++) static __gshared AA* edummies = null;

extern (D) this(Loc loc, Identifier ident, Type valType, Expression specValue, Expression defaultValue)
extern (D) this(Loc loc, Identifier ident, Type valType,
Expression specValue, Expression defaultValue)
{
super(loc, ident);
this.ident = ident;
Expand All @@ -4827,7 +4828,10 @@ public:

override TemplateParameter syntaxCopy()
{
return new TemplateValueParameter(loc, ident, valType.syntaxCopy(), specValue ? specValue.syntaxCopy() : null, defaultValue ? defaultValue.syntaxCopy() : null);
return new TemplateValueParameter(loc, ident,
valType.syntaxCopy(),
specValue ? specValue.syntaxCopy() : null,
defaultValue ? defaultValue.syntaxCopy() : null);
}

override bool declareParameter(Scope* sc)
Expand All @@ -4851,10 +4855,11 @@ public:
sc = sc.endCTFE();
e = e.implicitCastTo(sc, valType);
e = e.ctfeInterpret();
if (e.op == TOKint64 || e.op == TOKfloat64 || e.op == TOKcomplex80 || e.op == TOKnull || e.op == TOKstring)
if (e.op == TOKint64 || e.op == TOKfloat64 ||
e.op == TOKcomplex80 || e.op == TOKnull || e.op == TOKstring)
specValue = e;
//e->toInteger();
}

if (defaultValue)
{
Expression e = defaultValue;
Expand All @@ -4865,7 +4870,6 @@ public:
e = e.ctfeInterpret();
if (e.op == TOKint64)
defaultValue = e;
//e->toInteger();
}
}
return !isError(valType);
Expand Down Expand Up @@ -4904,20 +4908,27 @@ public:
return defaultValue !is null;
}

override MATCH matchArg(Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
override MATCH matchArg(Scope* sc, RootObject oarg,
size_t i, TemplateParameters* parameters, Objects* dedtypes,
Declaration* psparam)
{
//printf("TemplateValueParameter::matchArg('%s')\n", ident->toChars());
//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 = ei.semantic(sc);

/* If a function is really property-like, and then
* it's CTFEable, ei will be a literal expression.
*/
Expand All @@ -4926,6 +4937,7 @@ public:
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
Expand All @@ -4943,15 +4955,18 @@ public:
*/
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 = valType.semantic(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);
Expand All @@ -4963,17 +4978,21 @@ public:
ei = ei.implicitCastTo(sc, vt);
ei = ei.ctfeInterpret();
}

if (specValue)
{
if (!ei || cast(Expression)dmd_aaGetRvalue(edummies, cast(void*)ei.type) == ei)
goto Lnomatch;

Expression e = specValue;

sc = sc.startCTFE();
e = e.semantic(sc);
e = resolveProperties(sc, e);
sc = sc.endCTFE();
e = e.implicitCastTo(sc, vt);
e = e.ctfeInterpret();

ei = ei.syntaxCopy();
sc = sc.startCTFE();
ei = ei.semantic(sc);
Expand All @@ -4996,6 +5015,7 @@ public:
}
}
(*dedtypes)[i] = ei;

if (psparam)
{
Initializer _init = new ExpInitializer(loc, ei);
Expand All @@ -5004,6 +5024,7 @@ public:
*psparam = sparam;
}
return dependent ? MATCHexact : m;

Lnomatch:
//printf("\tno match\n");
if (psparam)
Expand Down
19 changes: 17 additions & 2 deletions src/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -3754,17 +3754,18 @@ public:
e = e.semantic(sc);
return e;
}
if (FuncLiteralDeclaration fld = s.isFuncLiteralDeclaration())
if (auto fld = s.isFuncLiteralDeclaration())
{
//printf("'%s' is a function literal\n", fld->toChars());
e = new FuncExp(loc, fld);
return e.semantic(sc);
}
if (FuncDeclaration f = s.isFuncDeclaration())
if (auto f = s.isFuncDeclaration())
{
f = f.toAliasFunc();
if (!f.functionSemantic())
return new ErrorExp();

if (!f.type.deco)
{
const(char)* trailMsg = f.inferRetType ? "inferred return type of function call " : "";
Expand Down Expand Up @@ -6165,6 +6166,20 @@ public:
assert(fd.fbody);
}

override bool equals(RootObject o)
{
if (this == o)
return true;
if (o.dyncast() != DYNCAST_EXPRESSION)
return false;
if ((cast(Expression)o).op == TOKfunction)
{
FuncExp fe = cast(FuncExp)o;
return fd == fe.fd;
}
return false;
}

void genIdent(Scope* sc)
{
if (fd.ident == Id.empty)
Expand Down
18 changes: 15 additions & 3 deletions src/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -6996,7 +6996,8 @@ public:
for (size_t i = 0; i < idents.dim; i++)
{
RootObject id = idents[i];
if (id.dyncast() == DYNCAST_EXPRESSION || id.dyncast() == DYNCAST_TYPE)
if (id.dyncast() == DYNCAST_EXPRESSION ||
id.dyncast() == DYNCAST_TYPE)
{
Type tx;
Expression ex;
Expand All @@ -7016,6 +7017,7 @@ public:
resolveExp(ex, pt, pe, ps);
return;
}

Type t = s.getType(); // type symbol, type alias, or type tuple?
uint errorsave = global.errors;
Dsymbol sm = s.searchX(loc, sc, id);
Expand All @@ -7029,7 +7031,8 @@ public:
goto L3;
if (VarDeclaration v = s.isVarDeclaration())
{
if (v.storage_class & (STCconst | STCimmutable | STCmanifest) || v.type.isConst() || v.type.isImmutable())
if (v.storage_class & (STCconst | STCimmutable | STCmanifest) ||
v.type.isConst() || v.type.isImmutable())
{
// Bugzilla 13087: this.field is not constant always
if (!v.isThisDeclaration())
Expand All @@ -7046,7 +7049,8 @@ public:
if (!t && s.isTupleDeclaration()) // expression tuple?
goto L3;
}
else if (s.isTemplateInstance() || s.isImport() || s.isPackage() || s.isModule())
else if (s.isTemplateInstance() ||
s.isImport() || s.isPackage() || s.isModule())
{
goto L3;
}
Expand Down Expand Up @@ -7134,6 +7138,13 @@ public:
*pe = new VarExp(loc, v);
return;
}
if (auto fld = s.isFuncLiteralDeclaration())
{
//printf("'%s' is a function literal\n", fld.toChars());
*pe = new FuncExp(loc, fld);
*pe = (*pe).semantic(sc);
return;
}
version (none)
{
if (FuncDeclaration fd = s.isFuncDeclaration())
Expand All @@ -7142,6 +7153,7 @@ public:
return;
}
}

L1:
Type t = s.getType();
if (!t)
Expand Down
30 changes: 30 additions & 0 deletions test/runnable/template9.d
Original file line number Diff line number Diff line change
Expand Up @@ -4727,6 +4727,36 @@ void test15152()
func!(s.name);
}

/******************************************/
// 15352

struct S15352(T, T delegate(uint idx) supplier)
{
}

auto make15352a(T, T delegate(uint idx) supplier)()
{
enum local = supplier; // OK
S15352!(T, local) ret;
return ret;
}

auto make15352b(T, T delegate(uint idx) supplier)()
{
S15352!(T, supplier) ret; // OK <- Error
return ret;
}

void test15352()
{
enum dg = delegate(uint idx) => idx;
auto s1 = S15352!(uint, dg)();
auto s2 = make15352a!(uint, dg)();
auto s3 = make15352b!(uint, dg)();
assert(is(typeof(s1) == typeof(s2)));
assert(is(typeof(s1) == typeof(s3)));
}

/******************************************/

int main()
Expand Down