diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 659701b02371..5c468721fd43 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -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 @@ -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 diff --git a/tests/neg/i16815.check b/tests/neg/i16815.check new file mode 100644 index 000000000000..8f2f5c57d405 --- /dev/null +++ b/tests/neg/i16815.check @@ -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 diff --git a/tests/neg/i16815.scala b/tests/neg/i16815.scala new file mode 100644 index 000000000000..595f75e40df4 --- /dev/null +++ b/tests/neg/i16815.scala @@ -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 = ???