Skip to content

Commit f55f055

Browse files
som-snyttjan-pieterSethTisueiusildraajafri2001
committed
Use other tree for actual symbol of Assign
Co-authored-by: Jan-Pieter van den Heuvel <jan-pieter@users.noreply.github.com> Co-authored-by: Seth Tisue <seth@tisue.net> Co-authored-by: Lucas Nouguier <iusildra@users.noreply.github.com> Co-authored-by: Prince <ajafri2001@users.noreply.github.com>
1 parent 18f22ab commit f55f055

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
@@ -1551,18 +1551,34 @@ class AmbiguousExtensionMethod(tree: untpd.Tree, expansion1: tpd.Tree, expansion
15511551
|are possible expansions of $tree"""
15521552
def explain(using Context) = ""
15531553

1554-
class ReassignmentToVal(name: Name)(using Context)
1555-
extends TypeMsg(ReassignmentToValID) {
1556-
def msg(using Context) = i"""Reassignment to val $name"""
1557-
def explain(using Context) =
1558-
i"""|You can not assign a new value to $name as values can't be changed.
1559-
|Keep in mind that every statement has a value, so you may e.g. use
1560-
| ${hl("val")} $name ${hl("= if (condition) 2 else 5")}
1561-
|In case you need a reassignable name, you can declare it as
1562-
|variable
1563-
| ${hl("var")} $name ${hl("=")} ...
1564-
|"""
1565-
}
1554+
class ReassignmentToVal(sym: Symbol, usage: Name, rhs: untpd.Tree)(using Context) extends TypeMsg(ReassignmentToValID):
1555+
val isSetter = usage.isSetterName && sym.info.firstParamTypes.nonEmpty
1556+
def msg(using Context) =
1557+
if isSetter then i"Bad assignment to setter should use $usage($rhs)"
1558+
else if sym.exists then i"Assignment to $sym"
1559+
else i"Bad assignment to $usage"
1560+
def explain(using Context) =
1561+
val name =
1562+
if isSetter then usage.asSimpleName.dropRight(2)
1563+
else if sym.exists then sym.name
1564+
else usage
1565+
if isSetter then
1566+
i"""|$usage is a setter name and can be used with assignment syntax:
1567+
| $name = $rhs
1568+
|"""
1569+
else
1570+
val addendum = if !sym.exists || !sym.owner.isClass || sym.isSetter then "" else
1571+
i"""|
1572+
|Assignment syntax can be used if there is a corresponding setter of the form:
1573+
| ${hl("def")} ${name}${hl(i"_=(x: ${sym.info.resultType}): Unit = ???")}
1574+
|"""
1575+
i"""|Members defined using `val` or `def` can't be assigned to.
1576+
|If you need to change the value of $name, use `var` instead:
1577+
| ${hl("var")} $name ${hl("=")} ???
1578+
|However, it's more common to initialize a variable just once
1579+
|with a complex expression or even a block with many statements:
1580+
| ${hl("val")} $name ${hl("= if (condition) 1 else -1")}$addendum
1581+
|"""
15661582

15671583
class TypeDoesNotTakeParameters(tpe: Type, params: List[untpd.Tree])(using Context)
15681584
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
@@ -1412,9 +1412,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14121412

14131413
def typedAssign(tree: untpd.Assign, pt: Type)(using Context): Tree =
14141414
tree.lhs match {
1415-
case lhs @ Apply(fn, args) =>
1416-
typed(untpd.Apply(untpd.Select(fn, nme.update), args :+ tree.rhs), pt)
1417-
case untpd.TypedSplice(Apply(MaybePoly(Select(fn, app), targs), args)) if app == nme.apply =>
1415+
case Apply(fn, args) =>
1416+
val appliedUpdate =
1417+
untpd.Apply(untpd.Select(fn, nme.update), args :+ tree.rhs)
1418+
typed(appliedUpdate, pt)
1419+
case untpd.TypedSplice(Apply(MaybePoly(Select(fn, nme.apply), targs), args)) =>
14181420
val rawUpdate: untpd.Tree = untpd.Select(untpd.TypedSplice(fn), nme.update)
14191421
val wrappedUpdate =
14201422
if (targs.isEmpty) rawUpdate
@@ -1428,7 +1430,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14281430
def lhs1 = adapt(lhsCore, LhsProto, locked)
14291431

14301432
def reassignmentToVal =
1431-
report.error(ReassignmentToVal(lhsCore.symbol.name), tree.srcPos)
1433+
val name = lhs match { case nt: NameTree => nt.name case _ => nme.NO_NAME }
1434+
report.error(ReassignmentToVal(lhs1.symbol `orElse` lhsCore.symbol, name, tree.rhs), tree.srcPos)
14321435
cpy.Assign(tree)(lhsCore, typed(tree.rhs, lhs1.tpe.widen)).withType(defn.UnitType)
14331436

14341437
def canAssign(sym: Symbol) =
@@ -1517,8 +1520,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
15171520
typedDynamicAssign(tree, pt)
15181521
case tpe =>
15191522
reassignmentToVal
1520-
}
1523+
}
15211524
}
1525+
end typedAssign
15221526

15231527
def typedBlockStats(stats: List[untpd.Tree])(using Context): (List[tpd.Tree], Context) =
15241528
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)