Skip to content

Commit 350aad4

Browse files
committed
fix param desugar in right-associative extensions
1 parent 9522b0f commit 350aad4

File tree

5 files changed

+57
-14
lines changed

5 files changed

+57
-14
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -908,20 +908,20 @@ object desugar {
908908
report.error(i"right-associative extension method $problem", mdef.srcPos)
909909
ext.paramss ++ mdef.paramss
910910
def noVParam = badRightAssoc("must start with a single parameter")
911-
def checkVparam(params: ParamClause) = params match
911+
def checkVparam(pre: List[ParamClause], params: ParamClause, paramss: List[ParamClause]) = params match
912912
case ValDefs(vparam :: Nil) =>
913913
if !vparam.mods.is(Given) then
914914
val (leadingUsing, otherExtParamss) = ext.paramss.span(isUsingOrTypeParamClause)
915-
leadingUsing ::: params1 :: otherExtParamss ::: paramss1
915+
leadingUsing ::: pre ::: params :: otherExtParamss ::: paramss
916916
else badRightAssoc("cannot start with using clause")
917917
case _ =>
918918
noVParam
919919
params1 match
920920
case TypeDefs(_) => paramss1 match
921-
case params2 :: _ => checkVparam(params2)
922-
case _ => noVParam
921+
case params2 :: paramss2 => checkVparam(params1::Nil, params2, paramss2)
922+
case _ => noVParam
923923
case _ =>
924-
checkVparam(params1)
924+
checkVparam(Nil, params1, paramss1)
925925

926926
case _ =>
927927
ext.paramss ++ mdef.paramss

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
251251
case TypeDefs(_) => true
252252
case _ => isUsingClause(params)
253253

254+
def isTypeParamClause(params: ParamClause)(using Context): Boolean = params match
255+
case TypeDefs(_) => true
256+
case _ => false
257+
254258
private val languageSubCategories = Set(nme.experimental, nme.deprecated)
255259

256260
/** If `path` looks like a language import, `Some(name)` where name

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -815,14 +815,16 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
815815
if isExtension then
816816
val paramss =
817817
if tree.name.isRightAssocOperatorName then
818-
// we have the encoding: leadingUsingOrTypeParams rightParam trailingUsing leftParam
819-
// we need to swap rightParam and leftParam
820-
val (leadingUsing, rest1) = tree.paramss.span(isUsingOrTypeParamClause)
821-
val (rightParamss, rest2) = rest1.splitAt(1)
822-
val (trailingUsing, rest3) = rest2.span(isUsingClause)
823-
val (leftParamss, rest4) = rest3.splitAt(1)
818+
// we have the encoding: leadingTy leadingUsing rightTyParamss rightParamss leftParamss trailingUsing
819+
// we need to swap (rightTyParams ++ rightParamss) with (leftParamss ++ trailingUsing)
820+
val (leadingTy, rest1) = tree.paramss.span(isTypeParamClause)
821+
val (leadingUsing, rest2) = rest1.span(isUsingClause)
822+
val (rightTyParamss, rest3) = rest2.span(isTypeParamClause)
823+
val (rightParamss, rest4) = rest3.splitAt(1)
824+
val (leftParamss, rest5) = rest4.splitAt(1)
825+
val (trailingUsing, rest6) = rest5.span(isUsingClause)
824826
if leftParamss.nonEmpty then
825-
leadingUsing ::: leftParamss ::: trailingUsing ::: rightParamss ::: rest4
827+
leadingTy ::: leadingUsing ::: leftParamss ::: trailingUsing ::: rightTyParamss ::: rightParamss ::: rest6
826828
else
827829
tree.paramss // it wasn't a binary operator, after all.
828830
else

tests/pos/i11583.scala

Lines changed: 0 additions & 2 deletions
This file was deleted.

tests/run/i11583.scala

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
class Context:
2+
type Type
3+
type Term
4+
5+
class Env:
6+
type Extra
7+
8+
// TODO: enable after https://github.com/lampepfl/dotty/issues/11700 is fixed
9+
// extension [Ctx <: Context](using ctx: Ctx)(tpe: ctx.Type)(using env: Env)
10+
// /** essentially: `extension (s: String) def &&:(b: Boolean)(i: Int)`
11+
// * but exercises the RefinedPrinter and safety of reordering parameters
12+
// */
13+
// def &&:[T <: ctx.Term](trm: T)(ext: env.Extra): (ctx.Type, T, env.Extra) = (tpe, trm, ext)
14+
15+
extension [Ctx <: Context](using ctx: Ctx)(tpe: String)(using env: Env)
16+
def :#:[T <: Boolean](trm: T)(ext: env.Extra): (String, T, env.Extra) = (tpe, trm, ext)
17+
18+
19+
extension (s: String)
20+
def :*:[T <: Tuple](t: T): String *: T = s *: t
21+
22+
@main def Test =
23+
24+
given Context with
25+
type Type = String
26+
type Term = Boolean
27+
28+
given Env with
29+
type Extra = Int
30+
31+
val t1: (String, Boolean, Int) = true.:#:("hello")(23)
32+
// val t2: (String, Boolean, Int) = true.&&:("hello")(23)
33+
val t3: (String, Boolean, Int) = "hello" :*: (true, 23)
34+
val t4: (String, Boolean, Int) = (true, 23).:*:("hello")
35+
36+
assert(t1 == ("hello", true, 23))
37+
// assert(t2 == ("hello", true, 23))
38+
assert(t3 == ("hello", true, 23))
39+
assert(t4 == ("hello", true, 23))

0 commit comments

Comments
 (0)