From 3dd34948f21c53bd8e39bd6a99dfdb340f12fcb7 Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Mon, 21 Oct 2024 19:51:53 +0200 Subject: [PATCH] Move AmbiguousNamedTupleAssignment check to Typer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Nicolas Stucki <3648029+nicolasstucki@users.noreply.github.com> Co-Authored-By: Oliver Bračevac --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 2 -- compiler/src/dotty/tools/dotc/typer/Typer.scala | 13 +++++++++++++ tests/pos/21681d.scala | 16 ++++++++++++++++ tests/warn/21681b.check | 7 +++++++ tests/warn/21681b.scala | 3 +++ 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/pos/21681d.scala create mode 100644 tests/warn/21681b.check create mode 100644 tests/warn/21681b.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 482210845fea..e66c71731b4f 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -1639,8 +1639,6 @@ object desugar { if ctx.mode.is(Mode.Type) then AppliedTypeTree(ref(defn.NamedTupleTypeRef), namesTuple :: tup :: Nil) else - if names.length == 1 && ctx.scope.lookup(names.head).is(Flags.Mutable) then - report.migrationWarning(AmbiguousNamedTupleAssignment(names.head, elemValues.head), tree.srcPos) Apply( Apply( TypeApply( diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 89ce01231fed..e7bd7d874634 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3398,6 +3398,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer /** Translate tuples of all arities */ def typedTuple(tree: untpd.Tuple, pt: Type)(using Context): Tree = val tree1 = desugar.tuple(tree, pt) + checkAmbiguousNamedTupleAssignment(tree) if tree1 ne tree then typed(tree1, pt) else val arity = tree.trees.length @@ -3423,6 +3424,18 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val resTpe = TypeOps.nestedPairs(elemTpes) app1.cast(resTpe) + /** Checks if `tree` is a named tuple with one element that could be + * interpreted as an assignment, such as `(x = 1)`. If so, issues a warning. + */ + def checkAmbiguousNamedTupleAssignment(tree: untpd.Tuple)(using Context): Unit = + tree.trees match + case List(NamedArg(name, value)) => + val typedName = typedIdent(untpd.Ident(name), WildcardType) + val sym = typedName.symbol + if sym.exists && (sym.is(Flags.Mutable) || sym.setter.exists) then + report.migrationWarning(AmbiguousNamedTupleAssignment(name, value), tree.srcPos) + case _ => () + /** Retrieve symbol attached to given tree */ protected def retrieveSym(tree: untpd.Tree)(using Context): Symbol = tree.removeAttachment(SymOfTree) match { case Some(sym) => diff --git a/tests/pos/21681d.scala b/tests/pos/21681d.scala new file mode 100644 index 000000000000..97a01dec74aa --- /dev/null +++ b/tests/pos/21681d.scala @@ -0,0 +1,16 @@ +def test1() = + class Person: + def age: Int = ??? + def age_=(x: Int): Unit = ??? + + val person = Person() + + (person.age = 29) // no warn (interpreted as `person.age_=(29)`) + +def test2() = + class Person: + var age: Int = 28 + + val person = Person() + + (person.age = 29) // no warn (interpreted as `person.age_=(29)`) diff --git a/tests/warn/21681b.check b/tests/warn/21681b.check new file mode 100644 index 000000000000..32760e00ebb6 --- /dev/null +++ b/tests/warn/21681b.check @@ -0,0 +1,7 @@ +-- [E203] Syntax Migration Warning: tests/warn/21681b.scala:3:2 -------------------------------------------------------- +3 | (age = 29) // warn + | ^^^^^^^^^^ + | Ambiguous syntax: this is interpreted as a named tuple with one element, + | not as an assignment. + | + | To assign a value, use curly braces: `{age = 29}`. diff --git a/tests/warn/21681b.scala b/tests/warn/21681b.scala new file mode 100644 index 000000000000..710d69b0dd23 --- /dev/null +++ b/tests/warn/21681b.scala @@ -0,0 +1,3 @@ +object Test: + var age: Int = 28 + (age = 29) // warn