Skip to content

Commit 76c6790

Browse files
committed
Use other tree for actual symbol of Assign
1 parent d519790 commit 76c6790

File tree

11 files changed

+255
-23
lines changed

11 files changed

+255
-23
lines changed

compiler/src/dotty/tools/dotc/ast/Trees.scala

+3-4
Original file line numberDiff line numberDiff line change
@@ -1821,16 +1821,15 @@ object Trees {
18211821
}
18221822
}
18231823

1824-
def rename(tree: NameTree, newName: Name)(using Context): tree.ThisTree[T] = {
1825-
tree match {
1824+
def rename(tree: NameTree, newName: Name)(using Context): tree.ThisTree[T] =
1825+
tree.match
18261826
case tree: Ident => cpy.Ident(tree)(newName)
18271827
case tree: Select => cpy.Select(tree)(tree.qualifier, newName)
18281828
case tree: Bind => cpy.Bind(tree)(newName, tree.body)
18291829
case tree: ValDef => cpy.ValDef(tree)(name = newName.asTermName)
18301830
case tree: DefDef => cpy.DefDef(tree)(name = newName.asTermName)
18311831
case tree: TypeDef => cpy.TypeDef(tree)(name = newName.asTypeName)
1832-
}
1833-
}.asInstanceOf[tree.ThisTree[T]]
1832+
.asInstanceOf[tree.ThisTree[T]]
18341833

18351834
object TypeDefs:
18361835
def unapply(xs: List[Tree]): Option[List[TypeDef]] = xs match

compiler/src/dotty/tools/dotc/reporting/messages.scala

+14-10
Original file line numberDiff line numberDiff line change
@@ -1526,18 +1526,22 @@ class AmbiguousExtensionMethod(tree: untpd.Tree, expansion1: tpd.Tree, expansion
15261526
|are possible expansions of $tree"""
15271527
def explain(using Context) = ""
15281528

1529-
class ReassignmentToVal(name: Name)(using Context)
1530-
extends TypeMsg(ReassignmentToValID) {
1531-
def msg(using Context) = i"""Reassignment to val $name"""
1532-
def explain(using Context) =
1533-
i"""|You can not assign a new value to $name as values can't be changed.
1534-
|Keep in mind that every statement has a value, so you may e.g. use
1535-
| ${hl("val")} $name ${hl("= if (condition) 2 else 5")}
1536-
|In case you need a reassignable name, you can declare it as
1537-
|variable
1529+
class ReassignmentToVal(sym: Symbol)(using Context) extends TypeMsg(ReassignmentToValID):
1530+
private def name = sym.name
1531+
private def addendum = if !sym.owner.isClass then "" else
1532+
i"""|
1533+
|Also, assignment syntax can be used if there is a corresponding setter:
1534+
| ${hl("def")} ${name}${hl("_=(x: Int): Unit = _v = x")}
1535+
|"""
1536+
def msg(using Context) = i"""Assignment to $sym"""
1537+
def explain(using Context) =
1538+
i"""|Members defined using `val` or `def` can't be assigned to.
1539+
|If you need to change the value of $name, use `var` instead:
15381540
| ${hl("var")} $name ${hl("=")} ...
1541+
|However, it's more common to initialize a variable just once
1542+
|with a complex expression or even a block with many statements:
1543+
| ${hl("val")} $name ${hl("= if (condition) 1 else -1")}$addendum
15391544
|"""
1540-
}
15411545

15421546
class TypeDoesNotTakeParameters(tpe: Type, params: List[untpd.Tree])(using Context)
15431547
extends TypeMsg(TypeDoesNotTakeParametersID) {

compiler/src/dotty/tools/dotc/typer/Dynamic.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ trait Dynamic {
137137
case TypeApply(sel @ Select(qual, name), targs) if !isDynamicMethod(name) =>
138138
typedDynamicAssign(qual, name, sel.span, targs)
139139
case _ =>
140-
errorTree(tree, ReassignmentToVal(tree.lhs.symbol.name))
140+
errorTree(tree, ReassignmentToVal(tree.lhs.symbol))
141141
}
142142
}
143143

compiler/src/dotty/tools/dotc/typer/Typer.scala

+8-5
Original file line numberDiff line numberDiff line change
@@ -1373,9 +1373,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
13731373

13741374
def typedAssign(tree: untpd.Assign, pt: Type)(using Context): Tree =
13751375
tree.lhs match {
1376-
case lhs @ Apply(fn, args) =>
1377-
typed(untpd.Apply(untpd.Select(fn, nme.update), args :+ tree.rhs), pt)
1378-
case untpd.TypedSplice(Apply(MaybePoly(Select(fn, app), targs), args)) if app == nme.apply =>
1376+
case Apply(fn, args) =>
1377+
val appliedUpdate =
1378+
untpd.Apply(untpd.Select(fn, nme.update), args :+ tree.rhs)
1379+
typed(appliedUpdate, pt)
1380+
case untpd.TypedSplice(Apply(MaybePoly(Select(fn, nme.apply), targs), args)) =>
13791381
val rawUpdate: untpd.Tree = untpd.Select(untpd.TypedSplice(fn), nme.update)
13801382
val wrappedUpdate =
13811383
if (targs.isEmpty) rawUpdate
@@ -1389,7 +1391,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
13891391
def lhs1 = adapt(lhsCore, LhsProto, locked)
13901392

13911393
def reassignmentToVal =
1392-
report.error(ReassignmentToVal(lhsCore.symbol.name), tree.srcPos)
1394+
report.error(ReassignmentToVal(lhs1.symbol), tree.srcPos)
13931395
cpy.Assign(tree)(lhsCore, typed(tree.rhs, lhs1.tpe.widen)).withType(defn.UnitType)
13941396

13951397
def canAssign(sym: Symbol) =
@@ -1478,8 +1480,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14781480
typedDynamicAssign(tree, pt)
14791481
case tpe =>
14801482
reassignmentToVal
1481-
}
1483+
}
14821484
}
1485+
end typedAssign
14831486

14841487
def typedBlockStats(stats: List[untpd.Tree])(using Context): (List[tpd.Tree], Context) =
14851488
index(stats)

tests/neg/i11561.check

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111
-- [E052] Type Error: tests/neg/i11561.scala:3:30 ----------------------------------------------------------------------
1212
3 | val updateText2 = copy(text = (_: String)) // error
1313
| ^^^^^^^^^^^^^^^^^^
14-
| Reassignment to val text
14+
| Assignment to value text
1515
|
1616
| longer explanation available when compiling with `-explain`

tests/neg/i16655.check

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-- [E052] Type Error: tests/neg/i16655.scala:3:4 -----------------------------------------------------------------------
22
3 | x = 5 // error
33
| ^^^^^
4-
| Reassignment to val x
4+
| Assignment to value x
55
|
66
| longer explanation available when compiling with `-explain`

tests/neg/i20338c.check

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-- [E052] Type Error: tests/neg/i20338c.scala:9:6 ----------------------------------------------------------------------
22
9 | f.x = 42 // error
33
| ^^^^^^^^
4-
| Reassignment to val x
4+
| Assignment to value x
55
|
66
| longer explanation available when compiling with `-explain`

tests/neg/i22671.check

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
-- [E007] Type Mismatch Error: tests/neg/i22671.scala:41:22 ------------------------------------------------------------
2+
41 | names_times(fields(0)) += fields(1).toLong // error
3+
| ^^^^^^^^^
4+
| Found: Char
5+
| Required: String
6+
|
7+
| longer explanation available when compiling with `-explain`
8+
-- [E008] Not Found Error: tests/neg/i22671.scala:45:6 -----------------------------------------------------------------
9+
45 | x() += "42" // error
10+
| ^^^^^^
11+
| value += is not a member of Int - did you mean Int.!=? or perhaps Int.<=?
12+
-- [E052] Type Error: tests/neg/i22671.scala:9:6 -----------------------------------------------------------------------
13+
9 | X.w = 27 // error
14+
| ^^^^^^^^
15+
| Assignment to value w
16+
|
17+
| longer explanation available when compiling with `-explain`
18+
-- [E052] Type Error: tests/neg/i22671.scala:12:6 ----------------------------------------------------------------------
19+
12 | X.x = 27 // error
20+
| ^^^^^^^^
21+
| Assignment to method x
22+
|
23+
| longer explanation available when compiling with `-explain`
24+
-- [E052] Type Error: tests/neg/i22671.scala:16:4 ----------------------------------------------------------------------
25+
16 | x = 27 // error
26+
| ^^^^^^
27+
| Assignment to method x
28+
|
29+
| longer explanation available when compiling with `-explain`
30+
-- [E052] Type Error: tests/neg/i22671.scala:20:4 ----------------------------------------------------------------------
31+
20 | y = 27 // error
32+
| ^^^^^^
33+
| Assignment to method x
34+
|
35+
| longer explanation available when compiling with `-explain`
36+
-- [E052] Type Error: tests/neg/i22671.scala:24:4 ----------------------------------------------------------------------
37+
24 | y = 27 // error
38+
| ^^^^^^
39+
| Assignment to value z
40+
|
41+
| longer explanation available when compiling with `-explain`
42+
-- [E052] Type Error: tests/neg/i22671.scala:28:4 ----------------------------------------------------------------------
43+
28 | x = 27 // error
44+
| ^^^^^^
45+
| Assignment to value x
46+
|
47+
| longer explanation available when compiling with `-explain`
48+
-- [E008] Not Found Error: tests/neg/i22671.scala:31:6 -----------------------------------------------------------------
49+
31 | X.x += 27 // error
50+
| ^^^^^^
51+
| value += is not a member of Int - did you mean Int.!=? or perhaps Int.<=?
52+
-- [E008] Not Found Error: tests/neg/i22671.scala:32:4 -----------------------------------------------------------------
53+
32 | 1 += 1 // error
54+
| ^^^^
55+
| value += is not a member of Int - did you mean (1 : Int).!=? or perhaps (1 : Int).<=?

tests/neg/i22671.explain.check

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
-- [E052] Type Error: tests/neg/i22671.explain.scala:14:6 --------------------------------------------------------------
2+
14 | X.w = 27 // error
3+
| ^^^^^^^^
4+
| Assignment to value w
5+
|--------------------------------------------------------------------------------------------------------------------
6+
| Explanation (enabled by `-explain`)
7+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8+
| Members defined using `val` or `def` can't be assigned to.
9+
| If you need to change the value of w, use `var` instead:
10+
| var w = ...
11+
| However, it's more common to initialize a variable just once
12+
| with a complex expression or even a block with many statements:
13+
| val w = if (condition) 1 else -1
14+
| Also, assignment syntax can be used if there is a corresponding setter:
15+
| def w_=(x: Int): Unit = _v = x
16+
--------------------------------------------------------------------------------------------------------------------
17+
-- [E052] Type Error: tests/neg/i22671.explain.scala:17:6 --------------------------------------------------------------
18+
17 | X.x = 27 // error
19+
| ^^^^^^^^
20+
| Assignment to method x
21+
|--------------------------------------------------------------------------------------------------------------------
22+
| Explanation (enabled by `-explain`)
23+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24+
| Members defined using `val` or `def` can't be assigned to.
25+
| If you need to change the value of x, use `var` instead:
26+
| var x = ...
27+
| However, it's more common to initialize a variable just once
28+
| with a complex expression or even a block with many statements:
29+
| val x = if (condition) 1 else -1
30+
| Also, assignment syntax can be used if there is a corresponding setter:
31+
| def x_=(x: Int): Unit = _v = x
32+
--------------------------------------------------------------------------------------------------------------------
33+
-- [E052] Type Error: tests/neg/i22671.explain.scala:21:4 --------------------------------------------------------------
34+
21 | y = 27 // error overload renamed
35+
| ^^^^^^
36+
| Assignment to method x
37+
|--------------------------------------------------------------------------------------------------------------------
38+
| Explanation (enabled by `-explain`)
39+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
40+
| Members defined using `val` or `def` can't be assigned to.
41+
| If you need to change the value of x, use `var` instead:
42+
| var x = ...
43+
| However, it's more common to initialize a variable just once
44+
| with a complex expression or even a block with many statements:
45+
| val x = if (condition) 1 else -1
46+
| Also, assignment syntax can be used if there is a corresponding setter:
47+
| def x_=(x: Int): Unit = _v = x
48+
--------------------------------------------------------------------------------------------------------------------
49+
-- [E052] Type Error: tests/neg/i22671.explain.scala:25:4 --------------------------------------------------------------
50+
25 | y = 27 // error val renamed
51+
| ^^^^^^
52+
| Assignment to value z
53+
|--------------------------------------------------------------------------------------------------------------------
54+
| Explanation (enabled by `-explain`)
55+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
56+
| Members defined using `val` or `def` can't be assigned to.
57+
| If you need to change the value of z, use `var` instead:
58+
| var z = ...
59+
| However, it's more common to initialize a variable just once
60+
| with a complex expression or even a block with many statements:
61+
| val z = if (condition) 1 else -1
62+
| Also, assignment syntax can be used if there is a corresponding setter:
63+
| def z_=(x: Int): Unit = _v = x
64+
--------------------------------------------------------------------------------------------------------------------
65+
-- [E052] Type Error: tests/neg/i22671.explain.scala:29:4 --------------------------------------------------------------
66+
29 | x = 27 // error local
67+
| ^^^^^^
68+
| Assignment to value x
69+
|--------------------------------------------------------------------------------------------------------------------
70+
| Explanation (enabled by `-explain`)
71+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
72+
| Members defined using `val` or `def` can't be assigned to.
73+
| If you need to change the value of x, use `var` instead:
74+
| var x = ...
75+
| However, it's more common to initialize a variable just once
76+
| with a complex expression or even a block with many statements:
77+
| val x = if (condition) 1 else -1
78+
--------------------------------------------------------------------------------------------------------------------
79+
-- [E052] Type Error: tests/neg/i22671.explain.scala:32:6 --------------------------------------------------------------
80+
32 | t.t = t // error
81+
| ^^^^^^^
82+
| Assignment to method t
83+
|--------------------------------------------------------------------------------------------------------------------
84+
| Explanation (enabled by `-explain`)
85+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
86+
| Members defined using `val` or `def` can't be assigned to.
87+
| If you need to change the value of t, use `var` instead:
88+
| var t = ...
89+
| However, it's more common to initialize a variable just once
90+
| with a complex expression or even a block with many statements:
91+
| val t = if (condition) 1 else -1
92+
| Also, assignment syntax can be used if there is a corresponding setter:
93+
| def t_=(x: Int): Unit = _v = x
94+
--------------------------------------------------------------------------------------------------------------------

tests/neg/i22671.explain.scala

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//> using options -explain
2+
3+
object X:
4+
val w: Int = 42
5+
def w(y: Int): Int = x + y
6+
def x: Int = 42
7+
def x(y: Int): Int = x + y
8+
val z = 26
9+
10+
trait T:
11+
def t = 42
12+
13+
def w =
14+
X.w = 27 // error
15+
16+
def f =
17+
X.x = 27 // error
18+
19+
def h =
20+
import X.x as y
21+
y = 27 // error overload renamed
22+
23+
def i =
24+
import X.z as y
25+
y = 27 // error val renamed
26+
27+
def j =
28+
val x = 42
29+
x = 27 // error local
30+
31+
def t(t: T) =
32+
t.t = t // error

tests/neg/i22671.scala

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
object X:
2+
val w: Int = 42
3+
def w(y: Int): Int = x + y
4+
def x: Int = 42
5+
def x(y: Int): Int = x + y
6+
val z = 26
7+
8+
def w =
9+
X.w = 27 // error
10+
11+
def f =
12+
X.x = 27 // error
13+
14+
def g =
15+
import X.x
16+
x = 27 // error
17+
18+
def h =
19+
import X.x as y
20+
y = 27 // error
21+
22+
def i =
23+
import X.z as y
24+
y = 27 // error
25+
26+
def j =
27+
val x = 42
28+
x = 27 // error
29+
30+
def k =
31+
X.x += 27 // error
32+
1 += 1 // error
33+
34+
35+
object t8763:
36+
import collection.mutable
37+
def bar(): Unit =
38+
val names_times = mutable.Map.empty[String, mutable.Set[Long]]
39+
val line = ""
40+
val Array(fields) = line.split("\t")
41+
names_times(fields(0)) += fields(1).toLong // error
42+
43+
object t9834:
44+
object x { def apply() = 42 ; def update(i: Int) = () }
45+
x() += "42" // error

0 commit comments

Comments
 (0)