diff --git a/compiler/src/dmd/opover.d b/compiler/src/dmd/opover.d index 6f6b7a95b353..acb3a586f647 100644 --- a/compiler/src/dmd/opover.d +++ b/compiler/src/dmd/opover.d @@ -551,14 +551,15 @@ Expression opOverloadBinary(BinExp e, Scope* sc, Type[2] aliasThisStop) // Try opBinary and opBinaryRight Dsymbol s = search_function(ad1, Id.opBinary); - if (s && !s.isTemplateDeclaration()) + + if (s && !(s.isTemplateDeclaration() || s.isOverloadSet)) { error(e.e1.loc, "`%s.opBinary` isn't a template", e.e1.toChars()); return ErrorExp.get(); } Dsymbol s_r = search_function(ad2, Id.opBinaryRight); - if (s_r && !s_r.isTemplateDeclaration()) + if (s_r && !(s_r.isTemplateDeclaration() || s_r.isOverloadSet())) { error(e.e2.loc, "`%s.opBinaryRight` isn't a template", e.e2.toChars()); return ErrorExp.get(); @@ -999,7 +1000,7 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt AggregateDeclaration ad1 = isAggregate(e.e1.type); Dsymbol s = search_function(ad1, Id.opOpAssign); - if (s && !s.isTemplateDeclaration()) + if (s && !(s.isTemplateDeclaration() || s.isOverloadSet())) { error(e.loc, "`%s.opOpAssign` isn't a template", e.e1.toChars()); return ErrorExp.get(); @@ -1187,6 +1188,8 @@ Dsymbol search_function(ScopeDsymbol ad, Identifier funcid) return fd; if (TemplateDeclaration td = s2.isTemplateDeclaration()) return td; + if (OverloadSet os = s2.isOverloadSet()) + return os; } return null; } diff --git a/compiler/src/dmd/typesem.d b/compiler/src/dmd/typesem.d index 6897b8574eb5..281b01b1e855 100644 --- a/compiler/src/dmd/typesem.d +++ b/compiler/src/dmd/typesem.d @@ -5013,17 +5013,32 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag /* Rewrite e.ident as: * e.opDispatch!("ident") */ - TemplateDeclaration td = fd.isTemplateDeclaration(); - if (!td) - { - .error(fd.loc, "%s `%s` must be a template `opDispatch(string s)`, not a %s", fd.kind, fd.toPrettyChars, fd.kind()); - return returnExp(ErrorExp.get()); - } - auto se = new StringExp(e.loc, ident.toString()); + auto tiargs = new Objects(); + auto se = new StringExp(e.loc, ident.toString()); tiargs.push(se); auto dti = new DotTemplateInstanceExp(e.loc, e, Id.opDispatch, tiargs); - dti.ti.tempdecl = td; + + if (OverloadSet os = fd.isOverloadSet()) + { + if (!findTempDecl(dti, sc)) + { + .error(fd.loc, "Couldn't find template declaration for opDispatch"); + return returnExp(ErrorExp.get()); + } + } + else + { + TemplateDeclaration td = fd.isTemplateDeclaration(); + if (!td) + { + .error(fd.loc, "%s `%s` must be a template `opDispatch(string s)`, not a %s", + fd.kind, fd.toPrettyChars, fd.kind()); + return returnExp(ErrorExp.get()); + } + dti.ti.tempdecl = td; + } + /* opDispatch, which doesn't need IFTI, may occur instantiate error. * e.g. * template opDispatch(name) if (isValid!name) { ... } diff --git a/compiler/test/fail_compilation/test21429.d b/compiler/test/fail_compilation/test21429.d new file mode 100644 index 000000000000..00ce85075032 --- /dev/null +++ b/compiler/test/fail_compilation/test21429.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test21429.d(20): Error: no property `z` for `s` of type `test21429.S` +fail_compilation/test21429.d(13): struct `S` defined here +--- +*/ +//make sure this fails properly after fixing bug 21429.d +template mixinOpDispatch(string id){ + string opDispatch(string s)() if(s == id){ return id; } +} + +struct S { + mixin mixinOpDispatch!"x"; + mixin mixinOpDispatch!"y"; +} + +void main(){ + S s; + auto fail = s.z; +} diff --git a/compiler/test/runnable/test21429.d b/compiler/test/runnable/test21429.d new file mode 100644 index 000000000000..c1d58113ff72 --- /dev/null +++ b/compiler/test/runnable/test21429.d @@ -0,0 +1,131 @@ +mixin template OD(string s) +{ + + string opDispatch(string name)() if (name == s) + { + return name; + } +} + +mixin template ODA(string s) +{ + void opDispatch(string name)(int x) if (name == s) + { + this.val = x; + } +} + +struct T +{ + mixin OD!"x"; + mixin OD!"y"; +} + +struct TAssign +{ + int val; + mixin ODA!"x"; + mixin ODA!"y"; +} + +struct U +{ + mixin OD!"z"; +} + + +template adder() +{ + int opBinary(string s : "+")(int x) { return x; } +} + +template subtracter() +{ + int opBinary(string s : "-")(int x) { return -x; } +} + + +struct Arithmetic +{ + mixin adder; + mixin subtracter; + +} + +template adderRight() +{ + int opBinaryRight(string s : "+")(int x){ return x; } +} + + +template subtracterRight() +{ + int opBinaryRight(string s: "-")(int x){ return -x; } +} + +struct ArithmeticRight +{ + mixin adderRight; + mixin subtracterRight; +} + +template mixinOpAssign(string op) +{ + void opOpAssign(string s)(int x) if(s == op) + { + val = x; + lastOp = s; + } +} + +struct AssignOverloads +{ + int val; + string lastOp; + mixin mixinOpAssign!"+"; + mixin mixinOpAssign!"-"; +} + + +void main() +{ + + T t; + string s = t.x(); + assert(s == "x"); + assert(t.y == "y"); + + //explicit call should work + assert(t.opDispatch!"x" == "x"); + + + //TODO: fix these + Arithmetic a; + assert((a + 5) == 5); + assert((a - 7) == -7); + + + ArithmeticRight ar; + assert((5 + ar) == 5); + assert((7 - ar) == -7); + + + U u; + //should work for a single mixin + assert(u.z == "z"); + + TAssign ta; + ta.x = 5; + assert(ta.val == 5); + ta.y = 10; + assert(ta.val == 10); + + AssignOverloads oa; + oa += 5; + assert(oa.val == 5); + assert(oa.lastOp == "+"); + oa -= 10; + assert(oa.val == 10); + assert(oa.lastOp == "-"); + +}