Skip to content

Commit

Permalink
Make right assoc ext method fwd refs error (#21641)
Browse files Browse the repository at this point in the history
Fixes #16815
  • Loading branch information
odersky authored Sep 26, 2024
2 parents f647651 + f684bac commit 27a4d8f
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 4 deletions.
20 changes: 16 additions & 4 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1099,8 +1099,8 @@ object desugar {
paramss match
case rightParam :: paramss1 => // `rightParam` must have a single parameter and without `given` flag

def badRightAssoc(problem: String) =
report.error(em"right-associative extension method $problem", mdef.srcPos)
def badRightAssoc(problem: String, pos: SrcPos) =
report.error(em"right-associative extension method $problem", pos)
extParamss ++ mdef.paramss

rightParam match
Expand All @@ -1116,11 +1116,23 @@ object desugar {
//
// If you change the names of the clauses below, also change them in right-associative-extension-methods.md
val (leftTyParamsAndLeadingUsing, leftParamAndTrailingUsing) = extParamss.span(isUsingOrTypeParamClause)

val names = (for ps <- mdef.paramss; p <- ps yield p.name).toSet[Name]

val tt = new untpd.UntypedTreeTraverser:
def traverse(tree: Tree)(using Context): Unit = tree match
case tree: Ident if names.contains(tree.name) =>
badRightAssoc(s"cannot have a forward reference to ${tree.name}", tree.srcPos)
case _ => traverseChildren(tree)

for ts <- leftParamAndTrailingUsing; t <- ts do
tt.traverse(t)

leftTyParamsAndLeadingUsing ::: rightTyParams ::: rightParam :: leftParamAndTrailingUsing ::: paramss1
else
badRightAssoc("cannot start with using clause")
badRightAssoc("cannot start with using clause", mdef.srcPos)
case _ =>
badRightAssoc("must start with a single parameter")
badRightAssoc("must start with a single parameter", mdef.srcPos)
case _ =>
// no value parameters, so not an infix operator.
extParamss ++ mdef.paramss
Expand Down
28 changes: 28 additions & 0 deletions tests/neg/i16815.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-- Error: tests/neg/i16815.scala:3:37 ----------------------------------------------------------------------------------
3 |extension [C1 >: Chain <: Chain](c2: c1.Tail) // error
| ^^
| right-associative extension method cannot have a forward reference to c1
-- Error: tests/neg/i16815.scala:6:24 ----------------------------------------------------------------------------------
6 |extension [C1](c2: (C1, C2)) // error
| ^^
| right-associative extension method cannot have a forward reference to C2
-- Error: tests/neg/i16815.scala:9:19 ----------------------------------------------------------------------------------
9 |extension [C1](c2: C2) // error
| ^^
| right-associative extension method cannot have a forward reference to C2
-- Error: tests/neg/i16815.scala:12:24 ---------------------------------------------------------------------------------
12 |extension [C1](c2: (C1, C2, C3)) // error // error
| ^^
| right-associative extension method cannot have a forward reference to C2
-- Error: tests/neg/i16815.scala:12:28 ---------------------------------------------------------------------------------
12 |extension [C1](c2: (C1, C2, C3)) // error // error
| ^^
| right-associative extension method cannot have a forward reference to C3
-- Error: tests/neg/i16815.scala:15:48 ---------------------------------------------------------------------------------
15 |extension [C1](str: String)(using z: (str.type, C2)) // error
| ^^
| right-associative extension method cannot have a forward reference to C2
-- Error: tests/neg/i16815.scala:19:31 ---------------------------------------------------------------------------------
19 |extension [D1 <: Int](D2: (D1, D2)) // error
| ^^
| right-associative extension method cannot have a forward reference to D2
20 changes: 20 additions & 0 deletions tests/neg/i16815.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
trait Chain { type Tail <: Chain }

extension [C1 >: Chain <: Chain](c2: c1.Tail) // error
def ra1_:[C2 <: C1](c1: C1): C2 = ???

extension [C1](c2: (C1, C2)) // error
def ra2_:[C2 <: C1](c1: (C1, C2)): C2 = ???

extension [C1](c2: C2) // error
def ra3_:[C2 <: C1](c1: C1): C2 = ???

extension [C1](c2: (C1, C2, C3)) // error // error
def ra4_:[C2 <: C1, C3 <: C1](c1: (C1, C2)): C2 = ???

extension [C1](str: String)(using z: (str.type, C2)) // error
def ra5_:[C2 <: Int](c1: C1): C2 = ???

type D2 = String
extension [D1 <: Int](D2: (D1, D2)) // error
def sa2_:[D2 <: D1](D1: (D1, D2)): D2 = ???

0 comments on commit 27a4d8f

Please sign in to comment.