diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 78d5dd9543ca..a4537133d89c 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -1794,7 +1794,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, out Expression pe0) if (i == 0) pe0 = extractOpDollarSideEffect(sc, ae); - if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration())) + if (e.op == EXP.interval && !slice) { return fallback(); } @@ -1821,21 +1821,27 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, out Expression pe0) if (auto ie = e.isIntervalExp()) { - Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t); - edim = edim.expressionSemantic(sc); - auto tiargs = new Objects(edim); - auto fargs = new Expressions(ie.lwr, ie.upr); + if (slice.isTemplateDeclaration()) + { + Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t); + edim = edim.expressionSemantic(sc); + auto tiargs = new Objects(edim); - const xerrors = global.startGagging(); - sc = sc.push(); - FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet); - sc = sc.pop(); - global.endGagging(xerrors); - if (!fslice) - return fallback(); + const xerrors = global.startGagging(); + sc = sc.push(); + FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet); + sc = sc.pop(); + global.endGagging(xerrors); + if (!fslice) + return fallback(); - e = new DotTemplateInstanceExp(ae.loc, ae.e1, Id.opSlice, tiargs); + e = new DotTemplateInstanceExp(ae.loc, ae.e1, Id.opSlice, tiargs); + } + else + { + e = new DotIdExp(ae.loc, ae.e1, Id.opSlice); + } e = new CallExp(ae.loc, e, fargs); e = e.expressionSemantic(sc); } diff --git a/compiler/test/runnable/opover3.d b/compiler/test/runnable/opover3.d index 980014016917..c6980bd37de5 100644 --- a/compiler/test/runnable/opover3.d +++ b/compiler/test/runnable/opover3.d @@ -195,6 +195,31 @@ void test20927() } /**************************************/ +// opSlice template argument for dimension 0 is optional +// https://github.com/dlang/dmd/issues/19447 +struct Foo +{ + int payload; + int opSlice(int start, int end) + { + return start * end; + } + auto opIndexAssign(T)(T elem, int slice) + { + this.payload = slice; + return this; + } +} + +void test19447() +{ + Foo foo; + foo[3 .. 5] = 15; + assert(foo.payload == 15); +} + +/**************************************/ + void main() { @@ -207,4 +232,5 @@ void main() test4(); test12070(); test20927(); + test19447(); } diff --git a/spec/operatoroverloading.dd b/spec/operatoroverloading.dd index 59bc56804d5c..1620d0baf72f 100644 --- a/spec/operatoroverloading.dd +++ b/spec/operatoroverloading.dd @@ -774,8 +774,12 @@ $(H3 $(LNAME2 slice_assignment_operator, Slice Assignment Operator Overloading)) `opIndexAssign` member function that takes the return value of the `opSlice` function as parameter(s). Expressions of the form $(CODE a[)$(SLICE)$(D ] = c) are rewritten as - $(CODE a.opIndexAssign$(LPAREN)c,) $(D a.opSlice!0$(LPAREN))$(SLICE2)$(D $(RPAREN)$(RPAREN)), - and $(CODE a[] = c) as $(CODE a.opIndexAssign(c)). + $(CODE a.opIndexAssign$(LPAREN)c,) $(D a.opSlice!0$(LPAREN))$(SLICE2)$(D $(RPAREN)$(RPAREN)) + when `opSlice` is a template, or + $(CODE a.opIndexAssign$(LPAREN)c,) $(D a.opSlice$(LPAREN))$(SLICE2)$(D $(RPAREN)$(RPAREN)) + when `opSlice` is declared without the compile-time parameter + (for one-dimensional slicing only). + $(CODE a[] = c) is rewritten as $(CODE a.opIndexAssign(c)). ) $(P See $(RELATIVE_LINK2 array-ops, Array