Skip to content

Commit fb79c19

Browse files
som-snyttjan-pieterSethTisueiusildraajafri2001
committed
Use other tree for actual symbol of Assign
Co-authored-by: Jan-Pieter van den Heuvel <[email protected]> Co-authored-by: Seth Tisue <[email protected]> Co-authored-by: Lucas Nouguier <[email protected]> Co-authored-by: Prince <[email protected]>
1 parent 2887c0a commit fb79c19

File tree

13 files changed

+306
-26
lines changed

13 files changed

+306
-26
lines changed

compiler/src/dotty/tools/dotc/printing/Formatting.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import core.*
88
import Texts.*, Types.*, Flags.*, Symbols.*, Contexts.*
99
import Decorators.*
1010
import reporting.Message
11-
import util.{DiffUtil, SimpleIdentitySet}
11+
import util.{Chars, DiffUtil, SimpleIdentitySet}
1212
import Highlighting.*
1313

1414
object Formatting {
@@ -184,7 +184,8 @@ object Formatting {
184184
}
185185

186186
def assemble(args: Seq[Shown])(using Context): String = {
187-
def isLineBreak(c: Char) = c == '\n' || c == '\f' // compatible with StringLike#isLineBreak
187+
// compatible with CharArrayReader (not StringOps)
188+
inline def isLineBreak(c: Char) = c == Chars.LF || c == Chars.FF
188189
def stripTrailingPart(s: String) = {
189190
val (pre, post) = s.span(c => !isLineBreak(c))
190191
pre ++ post.stripMargin

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

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,18 +1525,34 @@ class AmbiguousExtensionMethod(tree: untpd.Tree, expansion1: tpd.Tree, expansion
15251525
|are possible expansions of $tree"""
15261526
def explain(using Context) = ""
15271527

1528-
class ReassignmentToVal(name: Name)(using Context)
1529-
extends TypeMsg(ReassignmentToValID) {
1530-
def msg(using Context) = i"""Reassignment to val $name"""
1531-
def explain(using Context) =
1532-
i"""|You can not assign a new value to $name as values can't be changed.
1533-
|Keep in mind that every statement has a value, so you may e.g. use
1534-
| ${hl("val")} $name ${hl("= if (condition) 2 else 5")}
1535-
|In case you need a reassignable name, you can declare it as
1536-
|variable
1537-
| ${hl("var")} $name ${hl("=")} ...
1538-
|"""
1539-
}
1528+
class ReassignmentToVal(sym: Symbol, usage: Name, rhs: untpd.Tree)(using Context) extends TypeMsg(ReassignmentToValID):
1529+
val isSetter = usage.isSetterName && sym.info.firstParamTypes.nonEmpty
1530+
def msg(using Context) =
1531+
if isSetter then i"Bad assignment to setter should use $usage($rhs)"
1532+
else if sym.exists then i"Assignment to $sym"
1533+
else i"Bad assignment to $usage"
1534+
def explain(using Context) =
1535+
val name =
1536+
if isSetter then usage.asSimpleName.dropRight(2)
1537+
else if sym.exists then sym.name
1538+
else usage
1539+
if isSetter then
1540+
i"""|$usage is a setter name and can be used with assignment syntax:
1541+
| $name = $rhs
1542+
|"""
1543+
else
1544+
val addendum = if !sym.exists || !sym.owner.isClass || sym.isSetter then "" else
1545+
i"""|
1546+
|Assignment syntax can be used if there is a corresponding setter of the form:
1547+
| ${hl("def")} ${name}${hl(i"_=(x: ${sym.info.resultType}): Unit = ???")}
1548+
|"""
1549+
i"""|Members defined using `val` or `def` can't be assigned to.
1550+
|If you need to change the value of $name, use `var` instead:
1551+
| ${hl("var")} $name ${hl("=")} ???
1552+
|However, it's more common to initialize a variable just once
1553+
|with a complex expression or even a block with many statements:
1554+
| ${hl("val")} $name ${hl("= if (condition) 1 else -1")}$addendum
1555+
|"""
15401556

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

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,9 @@ trait Dynamic {
136136
typedDynamicAssign(qual, name, sel.span, Nil)
137137
case TypeApply(sel @ Select(qual, name), targs) if !isDynamicMethod(name) =>
138138
typedDynamicAssign(qual, name, sel.span, targs)
139-
case _ =>
140-
errorTree(tree, ReassignmentToVal(tree.lhs.symbol.name))
139+
case lhs =>
140+
val name = lhs match { case nt: NameTree => nt.name case _ => nme.NO_NAME }
141+
errorTree(tree, ReassignmentToVal(lhs.symbol, name, untpd.EmptyTree))
141142
}
142143
}
143144

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,9 +1400,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14001400

14011401
def typedAssign(tree: untpd.Assign, pt: Type)(using Context): Tree =
14021402
tree.lhs match {
1403-
case lhs @ Apply(fn, args) =>
1404-
typed(untpd.Apply(untpd.Select(fn, nme.update), args :+ tree.rhs), pt)
1405-
case untpd.TypedSplice(Apply(MaybePoly(Select(fn, app), targs), args)) if app == nme.apply =>
1403+
case Apply(fn, args) =>
1404+
val appliedUpdate =
1405+
untpd.Apply(untpd.Select(fn, nme.update), args :+ tree.rhs)
1406+
typed(appliedUpdate, pt)
1407+
case untpd.TypedSplice(Apply(MaybePoly(Select(fn, nme.apply), targs), args)) =>
14061408
val rawUpdate: untpd.Tree = untpd.Select(untpd.TypedSplice(fn), nme.update)
14071409
val wrappedUpdate =
14081410
if (targs.isEmpty) rawUpdate
@@ -1416,7 +1418,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14161418
def lhs1 = adapt(lhsCore, LhsProto, locked)
14171419

14181420
def reassignmentToVal =
1419-
report.error(ReassignmentToVal(lhsCore.symbol.name), tree.srcPos)
1421+
val name = lhs match { case nt: NameTree => nt.name case _ => nme.NO_NAME }
1422+
report.error(ReassignmentToVal(lhs1.symbol `orElse` lhsCore.symbol, name, tree.rhs), tree.srcPos)
14201423
cpy.Assign(tree)(lhsCore, typed(tree.rhs, lhs1.tpe.widen)).withType(defn.UnitType)
14211424

14221425
def canAssign(sym: Symbol) =
@@ -1505,8 +1508,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
15051508
typedDynamicAssign(tree, pt)
15061509
case tpe =>
15071510
reassignmentToVal
1508-
}
1511+
}
15091512
}
1513+
end typedAssign
15101514

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

tests/neg/assignments.check

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-- [E052] Type Error: tests/neg/assignments.scala:17:8 -----------------------------------------------------------------
2+
17 | x_= = 2 // error should give missing arguments, was: Reassignment to val x_=
3+
| ^^^^^^^
4+
| Bad assignment to setter should use x_=(2)
5+
|--------------------------------------------------------------------------------------------------------------------
6+
| Explanation (enabled by `-explain`)
7+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8+
| x_= is a setter name and can be used with assignment syntax:
9+
| x = 2
10+
--------------------------------------------------------------------------------------------------------------------
11+
-- [E083] Type Error: tests/neg/assignments.scala:20:9 -----------------------------------------------------------------
12+
20 | import c._ // error should give: prefix is not stable
13+
| ^
14+
| (assignments.c : assignments.C) is not a valid import prefix, since it is not an immutable path
15+
|--------------------------------------------------------------------------------------------------------------------
16+
| Explanation (enabled by `-explain`)
17+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
18+
| An immutable path is
19+
| - a reference to an immutable value, or
20+
| - a reference to `this`, or
21+
| - a selection of an immutable path with an immutable value.
22+
--------------------------------------------------------------------------------------------------------------------

tests/neg/assignments.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//> using options -explain
12
object assignments {
23

34
var a = Array(1, 2, 3)
@@ -13,9 +14,8 @@ object assignments {
1314
x = x + 1
1415
x *= 2
1516

16-
x_= = 2 // error should give missing arguments
17+
x_= = 2 // error should give missing arguments, was: Reassignment to val x_=
1718
}
18-
1919
var c = new C
2020
import c._ // error should give: prefix is not stable
2121
x = x + 1

tests/neg/i11561.check

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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:49:6 ----------------------------------------------------------------------
13+
49 | c = 42 // error
14+
| ^^^^^^
15+
| Assignment to value c
16+
|
17+
| longer explanation available when compiling with `-explain`
18+
-- [E052] Type Error: tests/neg/i22671.scala:9:6 -----------------------------------------------------------------------
19+
9 | X.w = 27 // error
20+
| ^^^^^^^^
21+
| Assignment to value w
22+
|
23+
| longer explanation available when compiling with `-explain`
24+
-- [E052] Type Error: tests/neg/i22671.scala:12:6 ----------------------------------------------------------------------
25+
12 | X.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:16:4 ----------------------------------------------------------------------
31+
16 | x = 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:20:4 ----------------------------------------------------------------------
37+
20 | y = 27 // error
38+
| ^^^^^^
39+
| Assignment to method x
40+
|
41+
| longer explanation available when compiling with `-explain`
42+
-- [E052] Type Error: tests/neg/i22671.scala:24:4 ----------------------------------------------------------------------
43+
24 | y = 27 // error
44+
| ^^^^^^
45+
| Assignment to value z
46+
|
47+
| longer explanation available when compiling with `-explain`
48+
-- [E052] Type Error: tests/neg/i22671.scala:28:4 ----------------------------------------------------------------------
49+
28 | x = 27 // error
50+
| ^^^^^^
51+
| Assignment to value x
52+
|
53+
| longer explanation available when compiling with `-explain`
54+
-- [E008] Not Found Error: tests/neg/i22671.scala:31:6 -----------------------------------------------------------------
55+
31 | X.x += 27 // error
56+
| ^^^^^^
57+
| value += is not a member of Int - did you mean Int.!=? or perhaps Int.<=?
58+
-- [E008] Not Found Error: tests/neg/i22671.scala:32:4 -----------------------------------------------------------------
59+
32 | 1 += 1 // error
60+
| ^^^^
61+
| value += is not a member of Int - did you mean (1 : Int).!=? or perhaps (1 : Int).<=?

0 commit comments

Comments
 (0)