Skip to content

Commit 2a62701

Browse files
authored
Disallow initializing fields with themself (#20696)
1 parent 2ecfa63 commit 2a62701

File tree

5 files changed

+70
-3
lines changed

5 files changed

+70
-3
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Initializing a field with itself has been deprecated
2+
3+
This is to prevent a common mistake when typing a simple constructor, where a parameter name is misspelled:
4+
5+
---
6+
struct S
7+
{
8+
int field;
9+
10+
this(int feild)
11+
{
12+
this.field = field; // equal to this.field = this.field
13+
}
14+
}
15+
---

compiler/src/dmd/expressionsem.d

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10604,6 +10604,35 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
1060410604
if (exp.op == EXP.assign
1060510605
&& exp.e1.checkModifiable(sc) == Modifiable.initialization)
1060610606
{
10607+
// Check common mistake of misspelled parameters in constructors,
10608+
// e.g. `this(int feild) { this.field = field; }`
10609+
if (auto dve1 = exp.e1.isDotVarExp)
10610+
if (auto dve2 = exp.e2.isDotVarExp)
10611+
if (sc.func && sc.func.parameters && dve1.e1.isThisExp && dve2.e1.isThisExp()
10612+
&& dve1.var.ident.equals(dve2.var.ident))
10613+
{
10614+
// @@@DEPRECATED_2.121@@@
10615+
// Deprecated in 2.111, make it an error in 2.121
10616+
deprecation(exp.e1.loc, "cannot initialize field `%s` with itself", dve1.var.toChars());
10617+
auto findParameter(const(char)[] s, ref int cost)
10618+
{
10619+
foreach (p; *sc.func.parameters)
10620+
{
10621+
if (p.ident.toString == s)
10622+
{
10623+
cost = 1;
10624+
return p.ident.toString;
10625+
}
10626+
}
10627+
return null;
10628+
}
10629+
import dmd.root.speller : speller;
10630+
if (auto s = speller!findParameter(dve1.var.ident.toString))
10631+
{
10632+
deprecationSupplemental(sc.func.loc, "did you mean to use parameter `%.*s`?\n", s.fTuple.expand);
10633+
}
10634+
}
10635+
1060710636
//printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
1060810637
auto t = exp.type;
1060910638
exp = new ConstructExp(exp.loc, exp.e1, exp.e2);

compiler/test/compilable/interpret3.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6240,9 +6240,9 @@ struct Coord13831
62406240

62416241
struct Chunk13831
62426242
{
6243-
this(Coord13831)
6243+
this(Coord13831 coord)
62446244
{
6245-
coord = coord;
6245+
this.coord = coord;
62466246
}
62476247

62486248
Coord13831 coord;

compiler/test/compilable/test22510.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ struct S
77
@disable this(this);
88
this (scope ref inout S) inout
99
{
10-
this.b = b;
10+
this.b = 0;
1111
}
1212
}
1313

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
REQUIRED_ARGS: -de
3+
TEST_OUTPUT:
4+
---
5+
fail_compilation/ctor_self_assignment.d(17): Deprecation: cannot initialize field `location` with itself
6+
fail_compilation/ctor_self_assignment.d(15): did you mean to use parameter `locaction`?
7+
---
8+
*/
9+
// https://forum.dlang.org/post/teghfhpmvkdcfwfeovua@forum.dlang.org
10+
11+
alias Location = int;
12+
13+
struct Node
14+
{
15+
this(Location locaction, uint f)
16+
{
17+
this.location = location;
18+
this.f = f;
19+
}
20+
21+
Location location;
22+
uint f;
23+
}

0 commit comments

Comments
 (0)