Skip to content

Commit 823206c

Browse files
authored
Merge pull request #11623 from rjolly/master
Fix desugaring of context bounds in extensions
2 parents 461258c + 1376302 commit 823206c

10 files changed

+95
-88
lines changed

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

Lines changed: 58 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -218,15 +218,32 @@ object desugar {
218218
* def f$default$2[T](x: Int) = x + "m"
219219
*/
220220
private def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(using Context): Tree =
221-
addDefaultGetters(elimContextBounds(meth, isPrimaryConstructor))
221+
addDefaultGetters(elimContextBounds(Nil, meth, isPrimaryConstructor))
222222

223-
private def elimContextBounds(meth: DefDef, isPrimaryConstructor: Boolean)(using Context): DefDef =
223+
private def defDef(extParamss: List[ParamClause], meth: DefDef)(using Context): Tree =
224+
addDefaultGetters(elimContextBounds(extParamss, meth, false))
225+
226+
private def elimContextBounds(extParamss: List[ParamClause], meth: DefDef, isPrimaryConstructor: Boolean)(using Context): DefDef =
224227
val DefDef(_, paramss, tpt, rhs) = meth
228+
229+
rhs match
230+
case MacroTree(call) =>
231+
cpy.DefDef(meth)(rhs = call).withMods(meth.mods | Macro | Erased)
232+
case _ =>
233+
cpy.DefDef(meth)(
234+
name = normalizeName(meth, tpt).asTermName,
235+
paramss =
236+
elimContextBounds(extParamss, isPrimaryConstructor, true) ++
237+
elimContextBounds(paramss, isPrimaryConstructor, false)
238+
)
239+
end elimContextBounds
240+
241+
private def elimContextBounds(paramss: List[ParamClause], isPrimaryConstructor: Boolean, ext: Boolean)(using Context): List[ParamClause] =
225242
val evidenceParamBuf = ListBuffer[ValDef]()
226243

227244
def desugarContextBounds(rhs: Tree): Tree = rhs match
228245
case ContextBounds(tbounds, cxbounds) =>
229-
val iflag = if sourceVersion.isAtLeast(`future`) then Given else Implicit
246+
val iflag = if ext || sourceVersion.isAtLeast(`future`) then Given else Implicit
230247
evidenceParamBuf ++= makeImplicitParameters(
231248
cxbounds, iflag, forPrimaryConstructor = isPrimaryConstructor)
232249
tbounds
@@ -240,15 +257,7 @@ object desugar {
240257
tparam => cpy.TypeDef(tparam)(rhs = desugarContextBounds(tparam.rhs))
241258
}(identity)
242259

243-
rhs match
244-
case MacroTree(call) =>
245-
cpy.DefDef(meth)(rhs = call).withMods(meth.mods | Macro | Erased)
246-
case _ =>
247-
addEvidenceParams(
248-
cpy.DefDef(meth)(
249-
name = normalizeName(meth, tpt).asTermName,
250-
paramss = paramssNoContextBounds),
251-
evidenceParamBuf.toList)
260+
addEvidenceParams(paramssNoContextBounds, evidenceParamBuf.toList)
252261
end elimContextBounds
253262

254263
def addDefaultGetters(meth: DefDef)(using Context): Tree =
@@ -348,22 +357,22 @@ object desugar {
348357
adaptToExpectedTpt(tree)
349358
}
350359

351-
/** Add all evidence parameters in `params` as implicit parameters to `meth`.
352-
* If the parameters of `meth` end in an implicit parameter list or using clause,
360+
/** Add all evidence parameters in `params` as implicit parameters to `paramss`.
361+
* If the parameters of `paramss` end in an implicit parameter list or using clause,
353362
* evidence parameters are added in front of that list. Otherwise they are added
354363
* as a separate parameter clause.
355364
*/
356-
private def addEvidenceParams(meth: DefDef, params: List[ValDef])(using Context): DefDef =
357-
params match
358-
case Nil =>
359-
meth
360-
case evidenceParams =>
361-
val paramss1 = meth.paramss.reverse match
362-
case ValDefs(vparams @ (vparam :: _)) :: rparamss if vparam.mods.isOneOf(GivenOrImplicit) =>
363-
((evidenceParams ++ vparams) :: rparamss).reverse
364-
case _ =>
365-
meth.paramss :+ evidenceParams
366-
cpy.DefDef(meth)(paramss = paramss1)
365+
366+
private def addEvidenceParams(paramss: List[ParamClause], params: List[ValDef])(using Context): List[ParamClause] =
367+
paramss.reverse match
368+
case ValDefs(vparams @ (vparam :: _)) :: rparamss if vparam.mods.isOneOf(GivenOrImplicit) =>
369+
((params ++ vparams) :: rparamss).reverse
370+
case _ =>
371+
params match
372+
case Nil =>
373+
paramss
374+
case evidenceParams =>
375+
paramss :+ evidenceParams
367376

368377
/** The implicit evidence parameters of `meth`, as generated by `desugar.defDef` */
369378
private def evidenceParams(meth: DefDef)(using Context): List[ValDef] =
@@ -487,9 +496,8 @@ object desugar {
487496
case ddef: DefDef if ddef.name.isConstructorName =>
488497
decompose(
489498
defDef(
490-
addEvidenceParams(
491-
cpy.DefDef(ddef)(paramss = joinParams(constrTparams, ddef.paramss)),
492-
evidenceParams(constr1).map(toDefParam(_, keepAnnotations = false, keepDefault = false)))))
499+
cpy.DefDef(ddef)(paramss = addEvidenceParams(joinParams(constrTparams, ddef.paramss),
500+
evidenceParams(constr1).map(toDefParam(_, keepAnnotations = false, keepDefault = false))))))
493501
case stat =>
494502
stat
495503
}
@@ -899,34 +907,29 @@ object desugar {
899907
/** Transform extension construct to list of extension methods */
900908
def extMethods(ext: ExtMethods)(using Context): Tree = flatTree {
901909
for mdef <- ext.methods yield
902-
defDef(
903-
cpy.DefDef(mdef)(
904-
name = normalizeName(mdef, ext).asTermName,
905-
paramss = mdef.paramss match
906-
case params1 :: paramss1 if mdef.name.isRightAssocOperatorName =>
907-
def badRightAssoc(problem: String) =
908-
report.error(i"right-associative extension method $problem", mdef.srcPos)
909-
ext.paramss ++ mdef.paramss
910-
def noVParam = badRightAssoc("must start with a single parameter")
911-
def checkVparam(params: ParamClause) = params match
912-
case ValDefs(vparam :: Nil) =>
913-
if !vparam.mods.is(Given) then
914-
val (leadingUsing, otherExtParamss) = ext.paramss.span(isUsingOrTypeParamClause)
915-
leadingUsing ::: params1 :: otherExtParamss ::: paramss1
916-
else badRightAssoc("cannot start with using clause")
917-
case _ =>
918-
noVParam
919-
params1 match
920-
case TypeDefs(_) => paramss1 match
921-
case params2 :: _ => checkVparam(params2)
922-
case _ => noVParam
923-
case _ =>
924-
checkVparam(params1)
925-
910+
def ret(ess: List[ParamClause], mss: List[ParamClause]) =
911+
defDef(
912+
ess,
913+
cpy.DefDef(mdef)(
914+
name = normalizeName(mdef, ext).asTermName,
915+
paramss = mss
916+
).withMods(mdef.mods | ExtensionMethod)
917+
)
918+
mdef.paramss match
919+
case params1 :: paramss1 if mdef.name.isRightAssocOperatorName =>
920+
def badRightAssoc(problem: String) =
921+
report.error(i"right-associative extension method $problem", mdef.srcPos)
922+
ret(ext.paramss, mdef.paramss)
923+
params1 match
924+
case ValDefs(vparam :: Nil) =>
925+
if !vparam.mods.is(Given) then
926+
val (leadingUsing, otherExtParamss) = ext.paramss.span(isUsingOrTypeParamClause)
927+
ret(Nil, leadingUsing ::: params1 :: otherExtParamss ::: paramss1)
928+
else badRightAssoc("cannot start with using clause")
926929
case _ =>
927-
ext.paramss ++ mdef.paramss
928-
).withMods(mdef.mods | ExtensionMethod)
929-
)
930+
badRightAssoc("must start with a single parameter")
931+
case _ =>
932+
ret(ext.paramss, mdef.paramss)
930933
}
931934

932935
/** Transforms

tests/neg/i10901.check

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
-- [E008] Not Found Error: tests/neg/i10901.scala:45:38 ----------------------------------------------------------------
22
45 | val pos1: Point2D[Int,Double] = x º y // error
33
| ^^^
4-
| value º is not a member of object BugExp4Point2D.IntT.
5-
| An extension method was tried, but could not be fully constructed:
4+
|value º is not a member of object BugExp4Point2D.IntT.
5+
|An extension method was tried, but could not be fully constructed:
66
|
7-
| º(x) failed with
7+
| º(x) failed with
88
|
9-
| Ambiguous overload. The overloaded alternatives of method º in object dsl with types
10-
| [T1, T2]
11-
| (x: BugExp4Point2D.ColumnType[T1])
12-
| (y: BugExp4Point2D.ColumnType[T2])
13-
| (implicit evidence$7: Numeric[T1], evidence$8: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
14-
| [T1, T2]
15-
| (x: T1)
16-
| (y: BugExp4Point2D.ColumnType[T2])
17-
| (implicit evidence$5: Numeric[T1], evidence$6: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
18-
| both match arguments ((x : BugExp4Point2D.IntT.type))
9+
| Ambiguous overload. The overloaded alternatives of method º in object dsl with types
10+
| [T1, T2]
11+
| (x: BugExp4Point2D.ColumnType[T1])
12+
| (y: BugExp4Point2D.ColumnType[T2])(using x$3: Numeric[T1], x$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
13+
| [T1, T2]
14+
| (x: T1)(y: BugExp4Point2D.ColumnType[T2])(using x$3: Numeric[T1], x$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
15+
| both match arguments ((x : BugExp4Point2D.IntT.type))
1916
-- [E008] Not Found Error: tests/neg/i10901.scala:48:38 ----------------------------------------------------------------
2017
48 | val pos4: Point2D[Int,Double] = x º 201.1 // error
2118
| ^^^
@@ -26,9 +23,8 @@
2623
|
2724
| Ambiguous overload. The overloaded alternatives of method º in object dsl with types
2825
| [T1, T2]
29-
| (x: BugExp4Point2D.ColumnType[T1])
30-
| (y: T2)(implicit evidence$9: Numeric[T1], evidence$10: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
31-
| [T1, T2](x: T1)(y: T2)(implicit evidence$3: Numeric[T1], evidence$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
26+
| (x: BugExp4Point2D.ColumnType[T1])(y: T2)(using x$3: Numeric[T1], x$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
27+
| [T1, T2](x: T1)(y: T2)(using x$3: Numeric[T1], x$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
3228
| both match arguments ((x : BugExp4Point2D.IntT.type))
3329
-- [E008] Not Found Error: tests/neg/i10901.scala:62:16 ----------------------------------------------------------------
3430
62 | val y = "abc".foo // error

tests/neg/i10901.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,27 @@ object BugExp4Point2D {
99
object dsl {
1010

1111

12-
extension [T1:Numeric, T2:Numeric](x: T1)
12+
extension [T1, T2](x: T1)
1313

1414
// N - N
1515
@targetName("point2DConstant")
16-
def º(y: T2): Point2D[T1,T2] = ???
16+
def º(y: T2)(using Numeric[T1], Numeric[T2]): Point2D[T1,T2] = ???
1717

1818

1919
// N - C
2020
@targetName("point2DConstantData")
21-
def º(y: ColumnType[T2]): Point2D[T1,T2] = ???
21+
def º(y: ColumnType[T2])(using Numeric[T1], Numeric[T2]): Point2D[T1,T2] = ???
2222

2323

2424

25-
extension [T1:Numeric, T2:Numeric](x: ColumnType[T1])
25+
extension [T1, T2](x: ColumnType[T1])
2626
// C - C
2727
@targetName("point2DData")
28-
def º(y: ColumnType[T2]): Point2D[T1,T2] = ???
28+
def º(y: ColumnType[T2])(using Numeric[T1], Numeric[T2]): Point2D[T1,T2] = ???
2929

3030
// C - N
3131
@targetName("point2DDataConstant")
32-
def º(y: T2): Point2D[T1,T2] = ???
32+
def º(y: T2)(using Numeric[T1], Numeric[T2]): Point2D[T1,T2] = ???
3333

3434

3535
}

tests/neg/missing-implicit1.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
-- Error: tests/neg/missing-implicit1.scala:23:42 ----------------------------------------------------------------------
2020
23 | List(1, 2, 3).traverse(x => Option(x)) // error
2121
| ^
22-
|no implicit argument of type testObjectInstance.Zip[Option] was found for an implicit parameter of method traverse in trait Traverse
22+
|no implicit argument of type testObjectInstance.Zip[Option] was found for parameter x$3 of method traverse in trait Traverse
2323
|
2424
|The following import might fix the problem:
2525
|

tests/neg/missing-implicit1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
object testObjectInstance:
22
trait Zip[F[_]]
33
trait Traverse[F[_]] {
4-
extension [A, B, G[_] : Zip](fa: F[A]) def traverse(f: A => G[B]): G[F[B]]
4+
extension [A, B, G[_]](fa: F[A]) def traverse(f: A => G[B])(using Zip[G]): G[F[B]]
55
}
66

77
object instances {

tests/neg/missing-implicit4.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
-- Error: tests/neg/missing-implicit4.scala:20:42 ----------------------------------------------------------------------
2020
20 | List(1, 2, 3).traverse(x => Option(x)) // error
2121
| ^
22-
|no implicit argument of type Zip[Option] was found for an implicit parameter of method traverse in trait Traverse
22+
| no implicit argument of type Zip[Option] was found for parameter x$3 of method traverse in trait Traverse
2323
|
24-
|The following import might fix the problem:
24+
| The following import might fix the problem:
2525
|
26-
| import instances.zipOption
26+
| import instances.zipOption
2727
|

tests/neg/missing-implicit4.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
def testLocalInstance =
22
trait Zip[F[_]]
33
trait Traverse[F[_]] {
4-
extension [A, B, G[_] : Zip](fa: F[A]) def traverse(f: A => G[B]): G[F[B]]
4+
extension [A, B, G[_]](fa: F[A]) def traverse(f: A => G[B])(using Zip[G]): G[F[B]]
55
}
66

77
object instances {

tests/pos/i11358.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ object Test:
99
def test7 = +++(IArray(1, 2))[Int](IArray(2, 3))
1010
def test8 = +++(IArray(1, 2))[Int](List(2, 3))
1111

12-
extension [A: reflect.ClassTag](arr: IArray[A])
13-
def +++[B >: A: reflect.ClassTag](suffix: IArray[B]): IArray[B] = ???
14-
def +++[B >: A: reflect.ClassTag](suffix: IterableOnce[B]): IArray[B] = ???
12+
extension [A](arr: IArray[A])
13+
def +++[B >: A](suffix: IArray[B])(using reflect.ClassTag[A], reflect.ClassTag[B]): IArray[B] = ???
14+
def +++[B >: A](suffix: IterableOnce[B])(using reflect.ClassTag[A], reflect.ClassTag[B]): IArray[B] = ???

tests/pos/i11583.scala

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

tests/pos/i11586.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
type Conv[T] = [X] =>> X => T
2+
3+
trait SemiGroup[T]:
4+
extension [U: Conv[T]](x: U)
5+
def combine(y: T): T
6+
extension (x: T)
7+
def combine[U: Conv[T]](y: U): T
8+
9+
trait Q[T, R: SemiGroup] extends SemiGroup[T]:
10+
def res(x: R, y: R) = x.combine(y)

0 commit comments

Comments
 (0)