From 4968ee606ff9285f1188117974c172c04a2fbe6a Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 24 Mar 2025 18:29:47 -0700 Subject: [PATCH] Use other tree for actual symbol of Assign Co-authored-by: Jan-Pieter van den Heuvel Co-authored-by: Seth Tisue Co-authored-by: Lucas Nouguier Co-authored-by: Prince --- .../tools/dotc/printing/Formatting.scala | 5 +- .../src/dotty/tools/dotc/typer/Dynamic.scala | 7 ++- .../src/dotty/tools/dotc/typer/Typer.scala | 7 ++- tests/neg/i22671.check | 61 +++++++++++++++++++ tests/neg/i22671.scala | 49 +++++++++++++++ 5 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 tests/neg/i22671.check create mode 100644 tests/neg/i22671.scala diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index daf4e70ad25a..cb37a5ea8a00 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -8,7 +8,7 @@ import core.* import Texts.*, Types.*, Flags.*, Symbols.*, Contexts.* import Decorators.* import reporting.Message -import util.{DiffUtil, SimpleIdentitySet} +import util.{Chars, DiffUtil, SimpleIdentitySet} import Highlighting.* object Formatting { @@ -184,7 +184,8 @@ object Formatting { } def assemble(args: Seq[Shown])(using Context): String = { - def isLineBreak(c: Char) = c == '\n' || c == '\f' // compatible with StringLike#isLineBreak + // compatible with CharArrayReader (not StringOps) + inline def isLineBreak(c: Char) = c == Chars.LF || c == Chars.FF def stripTrailingPart(s: String) = { val (pre, post) = s.span(c => !isLineBreak(c)) pre ++ post.stripMargin diff --git a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala index 8d48651ad6e9..7a05bfb8f8b0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala +++ b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala @@ -136,8 +136,11 @@ trait Dynamic { typedDynamicAssign(qual, name, sel.span, Nil) case TypeApply(sel @ Select(qual, name), targs) if !isDynamicMethod(name) => typedDynamicAssign(qual, name, sel.span, targs) - case _ => - errorTree(tree, ReassignmentToVal(tree.lhs.symbol.name, pt)) + case lhs => + val name = lhs match + case nt: NameTree => nt.name + case _ => lhs.symbol.name + errorTree(tree, ReassignmentToVal(name, pt)) } } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index fa952bae91da..6232b0304749 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1429,7 +1429,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer def lhs1 = adapt(lhsCore, LhsProto, locked) def reassignmentToVal = - report.error(ReassignmentToVal(lhsCore.symbol.name, pt), tree.srcPos) + val name = lhs match + case nt: NameTree => nt.name + case _ => lhs1.symbol.orElse(lhsCore.symbol).name + report.error(ReassignmentToVal(name, pt), tree.srcPos) cpy.Assign(tree)(lhsCore, typed(tree.rhs, lhs1.tpe.widen)).withType(defn.UnitType) def canAssign(sym: Symbol) = @@ -1518,7 +1521,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer typedDynamicAssign(tree, pt) case tpe => reassignmentToVal - } + } } def typedBlockStats(stats: List[untpd.Tree])(using Context): (List[tpd.Tree], Context) = diff --git a/tests/neg/i22671.check b/tests/neg/i22671.check new file mode 100644 index 000000000000..5de8d968a53b --- /dev/null +++ b/tests/neg/i22671.check @@ -0,0 +1,61 @@ +-- [E007] Type Mismatch Error: tests/neg/i22671.scala:41:22 ------------------------------------------------------------ +41 | names_times(fields(0)) += fields(1).toLong // error + | ^^^^^^^^^ + | Found: Char + | Required: String + | + | longer explanation available when compiling with `-explain` +-- [E008] Not Found Error: tests/neg/i22671.scala:45:6 ----------------------------------------------------------------- +45 | x() += "42" // error + | ^^^^^^ + | value += is not a member of Int - did you mean Int.!=? or perhaps Int.<=? +-- [E052] Type Error: tests/neg/i22671.scala:49:6 ---------------------------------------------------------------------- +49 | c = 42 // error + | ^^^^^^ + | Reassignment to val c + | + | longer explanation available when compiling with `-explain` +-- [E052] Type Error: tests/neg/i22671.scala:9:6 ----------------------------------------------------------------------- +9 | X.w = 27 // error + | ^^^^^^^^ + | Reassignment to val w + | + | longer explanation available when compiling with `-explain` +-- [E052] Type Error: tests/neg/i22671.scala:12:6 ---------------------------------------------------------------------- +12 | X.x = 27 // error + | ^^^^^^^^ + | Reassignment to val x + | + | longer explanation available when compiling with `-explain` +-- [E052] Type Error: tests/neg/i22671.scala:16:4 ---------------------------------------------------------------------- +16 | x = 27 // error + | ^^^^^^ + | Reassignment to val x + | + | longer explanation available when compiling with `-explain` +-- [E052] Type Error: tests/neg/i22671.scala:20:4 ---------------------------------------------------------------------- +20 | y = 27 // error + | ^^^^^^ + | Reassignment to val y + | + | longer explanation available when compiling with `-explain` +-- [E052] Type Error: tests/neg/i22671.scala:24:4 ---------------------------------------------------------------------- +24 | y = 27 // error + | ^^^^^^ + | Reassignment to val y + | + | longer explanation available when compiling with `-explain` +-- [E052] Type Error: tests/neg/i22671.scala:28:4 ---------------------------------------------------------------------- +28 | x = 27 // error + | ^^^^^^ + | Reassignment to val x + | + | longer explanation available when compiling with `-explain` +-- [E008] Not Found Error: tests/neg/i22671.scala:31:6 ----------------------------------------------------------------- +31 | X.x += 27 // error + | ^^^^^^ + | value += is not a member of Int - did you mean Int.!=? or perhaps Int.<=? +-- [E008] Not Found Error: tests/neg/i22671.scala:32:4 ----------------------------------------------------------------- +32 | 1 += 1 // error + | ^^^^ + | value += is not a member of Int - did you mean (1 : Int).!=? or perhaps (1 : Int).<=? diff --git a/tests/neg/i22671.scala b/tests/neg/i22671.scala new file mode 100644 index 000000000000..afb04f4cea73 --- /dev/null +++ b/tests/neg/i22671.scala @@ -0,0 +1,49 @@ +object X: + val w: Int = 42 + def w(y: Int): Int = x + y + def x: Int = 42 + def x(y: Int): Int = x + y + val z = 26 + +def w = + X.w = 27 // error + +def f = + X.x = 27 // error + +def g = + import X.x + x = 27 // error + +def h = + import X.x as y + y = 27 // error + +def i = + import X.z as y + y = 27 // error + +def j = + val x = 42 + x = 27 // error + +def k = + X.x += 27 // error + 1 += 1 // error + + +object t8763: + import collection.mutable + def bar(): Unit = + val names_times = mutable.Map.empty[String, mutable.Set[Long]] + val line = "" + val Array(fields) = line.split("\t") + names_times(fields(0)) += fields(1).toLong // error + +object t9834: + object x { def apply() = 42 ; def update(i: Int) = () } + x() += "42" // error + +class C(c: Int): + def test(): Unit = + c = 42 // error