Skip to content

Commit

Permalink
Move AmbiguousNamedTupleAssignment check to Typer
Browse files Browse the repository at this point in the history
Co-Authored-By: Nicolas Stucki <3648029+nicolasstucki@users.noreply.github.com>
Co-Authored-By: Oliver Bračevac <bracevac@users.noreply.github.com>
  • Loading branch information
3 people committed Oct 22, 2024
1 parent 8566f53 commit 3dd3494
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 2 deletions.
2 changes: 0 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
13 changes: 13 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) =>
Expand Down
16 changes: 16 additions & 0 deletions tests/pos/21681d.scala
Original file line number Diff line number Diff line change
@@ -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)`)
7 changes: 7 additions & 0 deletions tests/warn/21681b.check
Original file line number Diff line number Diff line change
@@ -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}`.
3 changes: 3 additions & 0 deletions tests/warn/21681b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object Test:
var age: Int = 28
(age = 29) // warn

0 comments on commit 3dd3494

Please sign in to comment.