diff --git a/changelog/dmd.deprecation-noop-assignment.dd b/changelog/dmd.deprecation-noop-assignment.dd new file mode 100644 index 0000000000..26e7fddabf --- /dev/null +++ b/changelog/dmd.deprecation-noop-assignment.dd @@ -0,0 +1,15 @@ +Initializing a field with itself has been deprecated + +This is to prevent a common mistake when typing a simple constructor, where a parameter name is misspelled: + +--- +struct S +{ + int field; + + this(int feild) + { + this.field = field; // equal to this.field = this.field + } +} +--- diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index eb4a5f884f..87c642c19d 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -10604,6 +10604,35 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.op == EXP.assign && exp.e1.checkModifiable(sc) == Modifiable.initialization) { + // Check common mistake of misspelled parameters in constructors, + // e.g. `this(int feild) { this.field = field; }` + if (auto dve1 = exp.e1.isDotVarExp) + if (auto dve2 = exp.e2.isDotVarExp) + if (sc.func && sc.func.parameters && dve1.e1.isThisExp && dve2.e1.isThisExp() + && dve1.var.ident.equals(dve2.var.ident)) + { + // @@@DEPRECATED_2.121@@@ + // Deprecated in 2.111, make it an error in 2.121 + deprecation(exp.e1.loc, "cannot initialize field `%s` with itself", dve1.var.toChars()); + auto findParameter(const(char)[] s, ref int cost) + { + foreach (p; *sc.func.parameters) + { + if (p.ident.toString == s) + { + cost = 1; + return p.ident.toString; + } + } + return null; + } + import dmd.root.speller : speller; + if (auto s = speller!findParameter(dve1.var.ident.toString)) + { + deprecationSupplemental(sc.func.loc, "did you mean to use parameter `%.*s`?\n", s.fTuple.expand); + } + } + //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars()); auto t = exp.type; exp = new ConstructExp(exp.loc, exp.e1, exp.e2); diff --git a/compiler/test/compilable/interpret3.d b/compiler/test/compilable/interpret3.d index aa88458ad7..f62147a0db 100644 --- a/compiler/test/compilable/interpret3.d +++ b/compiler/test/compilable/interpret3.d @@ -6240,9 +6240,9 @@ struct Coord13831 struct Chunk13831 { - this(Coord13831) + this(Coord13831 coord) { - coord = coord; + this.coord = coord; } Coord13831 coord; diff --git a/compiler/test/compilable/test22510.d b/compiler/test/compilable/test22510.d index af5d0a433e..1207bf0226 100644 --- a/compiler/test/compilable/test22510.d +++ b/compiler/test/compilable/test22510.d @@ -7,7 +7,7 @@ struct S @disable this(this); this (scope ref inout S) inout { - this.b = b; + this.b = 0; } } diff --git a/compiler/test/fail_compilation/ctor_self_assignment.d b/compiler/test/fail_compilation/ctor_self_assignment.d new file mode 100644 index 0000000000..9d424b1e86 --- /dev/null +++ b/compiler/test/fail_compilation/ctor_self_assignment.d @@ -0,0 +1,23 @@ +/** +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/ctor_self_assignment.d(17): Deprecation: cannot initialize field `location` with itself +fail_compilation/ctor_self_assignment.d(15): did you mean to use parameter `locaction`? +--- +*/ +// https://forum.dlang.org/post/teghfhpmvkdcfwfeovua@forum.dlang.org + +alias Location = int; + +struct Node +{ + this(Location locaction, uint f) + { + this.location = location; + this.f = f; + } + + Location location; + uint f; +}