From e8c1db34965d5a3a467f449552e244dd5596e74b Mon Sep 17 00:00:00 2001 From: Enno Runne Date: Thu, 11 May 2017 13:38:10 +0200 Subject: [PATCH 1/2] Move 'reassignment to val' to error case class --- .../reporting/diagnostic/ErrorMessageID.java | 1 + .../dotc/reporting/diagnostic/messages.scala | 14 ++++++++++++++ compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- .../dotc/reporting/ErrorMessagesTests.scala | 16 ++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index 73bec87c01df..166cfd6c7b21 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -57,6 +57,7 @@ public enum ErrorMessageID { CyclicReferenceInvolvingImplicitID, SuperQualMustBeParentID, AmbiguousImportID, + ReassignmentToValID, ; public int errorNumber() { diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index aa70443db42e..d93f2c7299ec 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1253,4 +1253,18 @@ object messages { |""" } + case class ReassignmentToVal(name: Names.Name)(implicit ctx: Context) + extends Message(ReassignmentToValID) { + val kind = "Reference" + val msg = hl"""reassignment to val `$name`""" + val explanation = + hl"""|You can not assign a new value to `$name` as values can't be changed. + |Keep in mind that every statement has a value, so you may e.g. use + | ${"val"} $name ${"= if (condition) 2 else 5"} + |In case you need a reassignable name, you can declare it as + |variable + | ${"var"} $name ${"="} ... + |""".stripMargin + } + } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index bc5d3c882bda..557e9b3e41d8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -558,7 +558,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def reassignmentToVal = errorTree(cpy.Assign(tree)(lhsCore, typed(tree.rhs, lhs1.tpe.widen)), - "reassignment to val") + ReassignmentToVal(lhsCore.symbol.name)) def canAssign(sym: Symbol) = sym.is(Mutable, butNot = Accessor) || diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 789d8e3cc9b1..53043ab57206 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -358,4 +358,20 @@ class ErrorMessagesTests extends ErrorMessagesTest { assertEquals(namedImport, newPrec) assertEquals(namedImport, prevPrec) } + + @Test def reassignmentToVal = + checkMessagesAfter("frontend") { + """ + |class Context { + | val value = 3 + | value = 4 + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ReassignmentToVal(name) :: Nil = messages + assertEquals("value", name.show) + } } From f499a1fd7fde8d28949024c6679a9861ae75d183 Mon Sep 17 00:00:00 2001 From: Enno Runne Date: Thu, 11 May 2017 22:00:28 +0200 Subject: [PATCH 2/2] Use 'reassignment to val' message as error in Dynamic --- compiler/src/dotty/tools/dotc/typer/Dynamic.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala index 25fca546e6db..1d6643763365 100644 --- a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala +++ b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala @@ -15,6 +15,7 @@ import core.Symbols._ import core.Definitions import Inferencing._ import ErrorReporting._ +import dotty.tools.dotc.reporting.diagnostic.messages.ReassignmentToVal object Dynamic { def isDynamicMethod(name: Name): Boolean = @@ -99,7 +100,7 @@ trait Dynamic { self: Typer with Applications => case TypeApply(Select(qual, name), targs) if !isDynamicMethod(name) => typedDynamicAssign(qual, name, targs) case _ => - errorTree(tree, "reassignment to val") + errorTree(tree, ReassignmentToVal(tree.lhs.symbol.name)) } }