Skip to content

Commit 73bcb78

Browse files
committed
Fix desugaring of context bounds in extensions
Fixes #11586 Unfixes #11583
1 parent 5e0100d commit 73bcb78

File tree

3 files changed

+68
-57
lines changed

3 files changed

+68
-57
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, false))
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, true))
225+
226+
private def elimContextBounds(extParamss: List[ParamClause], meth: DefDef, isPrimaryConstructor: Boolean, ext: 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, ext) ++
237+
elimContextBounds(paramss, isPrimaryConstructor, ext)
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
}
@@ -906,34 +914,29 @@ object desugar {
906914
/** Transform extension construct to list of extension methods */
907915
def extMethods(ext: ExtMethods)(using Context): Tree = flatTree {
908916
for mdef <- ext.methods yield
909-
defDef(
910-
cpy.DefDef(mdef)(
911-
name = normalizeName(mdef, ext).asTermName,
912-
paramss = mdef.paramss match
913-
case params1 :: paramss1 if mdef.name.isRightAssocOperatorName =>
914-
def badRightAssoc(problem: String) =
915-
report.error(i"right-associative extension method $problem", mdef.srcPos)
916-
ext.paramss ++ mdef.paramss
917-
def noVParam = badRightAssoc("must start with a single parameter")
918-
def checkVparam(params: ParamClause) = params match
919-
case ValDefs(vparam :: Nil) =>
920-
if !vparam.mods.is(Given) then
921-
val (leadingUsing, otherExtParamss) = ext.paramss.span(isUsingOrTypeParamClause)
922-
leadingUsing ::: params1 :: otherExtParamss ::: paramss1
923-
else badRightAssoc("cannot start with using clause")
924-
case _ =>
925-
noVParam
926-
params1 match
927-
case TypeDefs(_) => paramss1 match
928-
case params2 :: _ => checkVparam(params2)
929-
case _ => noVParam
930-
case _ =>
931-
checkVparam(params1)
932-
917+
def ret(ess: List[ParamClause], mss: List[ParamClause]) =
918+
defDef(
919+
ess,
920+
cpy.DefDef(mdef)(
921+
name = normalizeName(mdef, ext).asTermName,
922+
paramss = mss
923+
).withMods(mdef.mods | ExtensionMethod)
924+
)
925+
mdef.paramss match
926+
case params1 :: paramss1 if mdef.name.isRightAssocOperatorName =>
927+
def badRightAssoc(problem: String) =
928+
report.error(i"right-associative extension method $problem", mdef.srcPos)
929+
ret(ext.paramss, mdef.paramss)
930+
params1 match
931+
case ValDefs(vparam :: Nil) =>
932+
if !vparam.mods.is(Given) then
933+
val (leadingUsing, otherExtParamss) = ext.paramss.span(isUsingOrTypeParamClause)
934+
ret(Nil, leadingUsing ::: params1 :: otherExtParamss ::: paramss1)
935+
else badRightAssoc("cannot start with using clause")
933936
case _ =>
934-
ext.paramss ++ mdef.paramss
935-
).withMods(mdef.mods | ExtensionMethod)
936-
)
937+
badRightAssoc("must start with a single parameter")
938+
case _ =>
939+
ret(ext.paramss, mdef.paramss)
937940
}
938941

939942
/** Transforms

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)