Skip to content

Commit dfa9240

Browse files
committed
Reuse addEvidenceParams logic, but no aliases
1 parent ec6d7ef commit dfa9240

File tree

3 files changed

+147
-76
lines changed

3 files changed

+147
-76
lines changed

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

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import parsing.Parsers
2222

2323
import scala.annotation.internal.sharable
2424
import scala.annotation.threadUnsafe
25+
import dotty.tools.dotc.quoted.QuoteUtils.treeOwner
2526

2627
object desugar {
2728
import untpd.*
@@ -52,8 +53,12 @@ object desugar {
5253
*/
5354
val ContextBoundParam: Property.Key[Unit] = Property.StickyKey()
5455

55-
/** An attachment key to indicate that a DefDef is a poly function apply
56-
* method definition.
56+
/** When first desugaring a PolyFunction, this attachment is added to the
57+
* PolyFunction `apply` method with an empty list value.
58+
*
59+
* Afterwards, the attachment is added to poly function type trees, with the
60+
* list of their context bounds.
61+
* //TODO(kπ) see if it has to be updated
5762
*/
5863
val PolyFunctionApply: Property.Key[List[ValDef]] = Property.StickyKey()
5964

@@ -497,9 +502,9 @@ object desugar {
497502
case Ident(name: TermName) => boundNames.contains(name)
498503
case _ => false
499504

500-
def recur(mparamss: List[ParamClause]): List[ParamClause] = mparamss match
505+
def recur(mparamss: List[ParamClause]): (List[ParamClause], List[ParamClause]) = mparamss match
501506
case ValDefs(mparams) :: _ if mparams.exists(referencesBoundName) =>
502-
params :: mparamss
507+
(params :: Nil) -> mparamss
503508
case ValDefs(mparams @ (mparam :: _)) :: Nil if mparam.mods.isOneOf(GivenOrImplicit) =>
504509
val normParams =
505510
if params.head.mods.flags.is(Given) != mparam.mods.flags.is(Given) then
@@ -508,30 +513,71 @@ object desugar {
508513
param.withMods(param.mods.withFlags(normFlags))
509514
.showing(i"adapted param $result ${result.mods.flags} for ${meth.name}", Printers.desugar)
510515
else params
511-
(normParams ++ mparams) :: Nil
516+
((normParams ++ mparams) :: Nil) -> Nil
512517
case mparams :: mparamss1 =>
513-
mparams :: recur(mparamss1)
518+
val (fst, snd) = recur(mparamss1)
519+
(mparams :: fst) -> snd
514520
case Nil =>
515-
params :: Nil
516-
517-
def pushDownEvidenceParams(tree: Tree): Tree = tree match
518-
case Function(params, body) =>
519-
cpy.Function(tree)(params, pushDownEvidenceParams(body))
520-
case Block(stats, expr) =>
521-
cpy.Block(tree)(stats, pushDownEvidenceParams(expr))
522-
case tree =>
521+
Nil -> (params :: Nil)
522+
523+
// def pushDownEvidenceParams(tree: Tree): Tree = tree match
524+
// case Function(mparams, body) if mparams.collect { case v: ValDef => v }.exists(referencesBoundName) =>
525+
// ctxFunctionWithParams(tree)
526+
// case Function(mparams, body) =>
527+
// cpy.Function(tree)(mparams, pushDownEvidenceParams(body))
528+
// case Block(stats, expr) =>
529+
// cpy.Block(tree)(stats, pushDownEvidenceParams(expr))
530+
// case tree =>
531+
// ctxFunctionWithParams(tree)
532+
533+
// def ctxFunctionWithParams(tree: Tree): Tree =
534+
// val paramTpts = params.map(_.tpt)
535+
// val paramNames = params.map(_.name)
536+
// val paramsErased = params.map(_.mods.flags.is(Erased))
537+
// Function(params, tree).withSpan(tree.span).withAttachmentsFrom(tree)
538+
539+
def functionsOf(paramss: List[ParamClause], rhs: Tree): Tree = paramss match
540+
case Nil => rhs
541+
case ValDefs(head @ (fst :: _)) :: rest if fst.mods.isOneOf(GivenOrImplicit) =>
523542
val paramTpts = params.map(_.tpt)
524543
val paramNames = params.map(_.name)
525544
val paramsErased = params.map(_.mods.flags.is(Erased))
526-
makeContextualFunction(paramTpts, paramNames, tree, paramsErased).withSpan(tree.span)
545+
makeContextualFunction(paramTpts, paramNames, functionsOf(rest, rhs), paramsErased).withSpan(rhs.span)
546+
case head :: rest =>
547+
Function(head, functionsOf(rest, rhs))
527548

528549
if meth.hasAttachment(PolyFunctionApply) then
529-
if ctx.mode.is(Mode.Type) then
530-
cpy.DefDef(meth)(tpt = meth.tpt.withAttachment(PolyFunctionApply, params))
531-
else
532-
cpy.DefDef(meth)(rhs = pushDownEvidenceParams(meth.rhs))
550+
println(i"${recur(meth.paramss)}")
551+
recur(meth.paramss) match
552+
case (paramsFst, Nil) =>
553+
cpy.DefDef(meth)(paramss = paramsFst)
554+
case (paramsFst, paramsSnd) =>
555+
if ctx.mode.is(Mode.Type) then
556+
cpy.DefDef(meth)(paramss = paramsFst, tpt = functionsOf(paramsSnd, meth.tpt))
557+
else
558+
cpy.DefDef(meth)(paramss = paramsFst, rhs = functionsOf(paramsSnd, meth.rhs))
559+
560+
// if ctx.mode.is(Mode.Type) then
561+
// meth.removeAttachment(PolyFunctionApply)
562+
// // should be kept on meth to see the current param types?
563+
// meth.tpt.putAttachment(PolyFunctionApply, params)
564+
// val newParamss = recur(meth.paramss)
565+
// println(i"added PolyFunctionApply to ${meth.name}.tpt: ${meth.tpt} with $params")
566+
// println(i"new paramss: $newParamss")
567+
// meth
568+
// else
569+
// val newParamss = recur(meth.paramss)
570+
// println(i"added PolyFunctionApply to ${meth.name} with $params")
571+
// println(i"new paramss: $newParamss")
572+
// val DefDef(_, mparamss, _ , _) = meth: @unchecked
573+
// val tparams :: ValDefs(vparams) :: Nil = mparamss: @unchecked
574+
// if vparams.exists(referencesBoundName) then
575+
// cpy.DefDef(meth)(paramss = tparams :: params :: Nil, rhs = Function(vparams, meth.rhs))
576+
// else
577+
// cpy.DefDef(meth)(rhs = pushDownEvidenceParams(meth.rhs))
533578
else
534-
cpy.DefDef(meth)(paramss = recur(meth.paramss))
579+
val (paramsFst, paramsSnd) = recur(meth.paramss)
580+
cpy.DefDef(meth)(paramss = paramsFst ++ paramsSnd)
535581
end addEvidenceParams
536582

537583
/** The parameters generated from the contextual bounds of `meth`, as generated by `desugar.defDef` */
@@ -1265,17 +1311,20 @@ object desugar {
12651311
case ((p, paramFlags), n) => makeSyntheticParameter(n + 1, p).withAddedFlags(paramFlags)
12661312
}.toList
12671313

1314+
vparams.foreach(p => println(i" $p, ${p.mods.flags.flagsString}"))
12681315
RefinedTypeTree(ref(defn.PolyFunctionType), List(
12691316
DefDef(nme.apply, tparams :: vparams :: Nil, res, EmptyTree)
12701317
.withFlags(Synthetic)
12711318
.withAttachment(PolyFunctionApply, List.empty)
12721319
)).withSpan(tree.span)
1320+
.withAttachment(PolyFunctionApply, tree.attachmentOrElse(PolyFunctionApply, List.empty))
12731321
case PolyFunction(tparams: List[untpd.TypeDef] @unchecked, res) =>
12741322
RefinedTypeTree(ref(defn.PolyFunctionType), List(
12751323
DefDef(nme.apply, tparams :: Nil, res, EmptyTree)
12761324
.withFlags(Synthetic)
12771325
.withAttachment(PolyFunctionApply, List.empty)
12781326
)).withSpan(tree.span)
1327+
.withAttachment(PolyFunctionApply, tree.attachmentOrElse(PolyFunctionApply, List.empty))
12791328
end makePolyFunctionType
12801329

12811330
/** Invent a name for an anonympus given of type or template `impl`. */

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 51 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3592,61 +3592,62 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
35923592
}
35933593
}
35943594

3595-
/** Push down the deferred evidence parameters up until the result type is not
3596-
* a method type, poly type or a function type
3597-
*/
3598-
private def pushDownDeferredEvidenceParams(tpe: Type, params: List[untpd.ValDef], span: Span)(using Context): Type = tpe.dealias match {
3599-
case tpe: MethodType =>
3600-
tpe.derivedLambdaType(tpe.paramNames, tpe.paramInfos, pushDownDeferredEvidenceParams(tpe.resultType, params, span))
3601-
case tpe: PolyType =>
3602-
tpe.derivedLambdaType(tpe.paramNames, tpe.paramInfos, pushDownDeferredEvidenceParams(tpe.resultType, params, span))
3603-
case tpe: RefinedType =>
3604-
tpe.derivedRefinedType(
3605-
pushDownDeferredEvidenceParams(tpe.parent, params, span),
3606-
tpe.refinedName,
3607-
pushDownDeferredEvidenceParams(tpe.refinedInfo, params, span)
3608-
)
3609-
case tpe @ AppliedType(tycon, args) if defn.isFunctionType(tpe) && args.size > 1 =>
3610-
tpe.derivedAppliedType(tycon, args.init :+ pushDownDeferredEvidenceParams(args.last, params, span))
3611-
case tpe =>
3612-
val paramNames = params.map(_.name)
3613-
val paramTpts = params.map(_.tpt)
3614-
val paramsErased = params.map(_.mods.flags.is(Erased))
3615-
val ctxFunction = desugar.makeContextualFunction(paramTpts, paramNames, untpd.TypedSplice(TypeTree(tpe.dealias)), paramsErased).withSpan(span)
3616-
typed(ctxFunction).tpe
3617-
}
3618-
3619-
/** If the tree has a `PolyFunctionApply` attachment, add the deferred
3620-
* evidence parameters as the last argument list before the result type. This
3621-
* follows aliases, so the following two types will be expanded to (up to the
3622-
* context bound encoding):
3623-
* type CmpWeak[X] = X => Boolean
3624-
* type Comparer2Weak = [X: Ord] => X => CmpWeak[X]
3625-
* ===>
3626-
* type CmpWeak[X] = X => Boolean type Comparer2Weak = [X] => X => X ?=>
3627-
* Ord[X] => Boolean
3628-
*/
3629-
private def addDeferredEvidenceParams(tree: Tree, pt: Type)(using Context): (Tree, Type) = {
3630-
tree.getAttachment(desugar.PolyFunctionApply) match
3631-
case Some(params) if params.nonEmpty =>
3632-
tree.removeAttachment(desugar.PolyFunctionApply)
3633-
val tpe = pushDownDeferredEvidenceParams(tree.tpe, params, tree.span)
3634-
TypeTree(tpe).withSpan(tree.span) -> tpe
3635-
case _ => tree -> pt
3636-
}
3595+
// /** Push down the deferred evidence parameters up until the result type is not
3596+
// * a method type, poly type or a function type
3597+
// */
3598+
// private def pushDownDeferredEvidenceParams(tpe: Type, params: List[untpd.ValDef], span: Span)(using Context): Type =
3599+
// tpe.dealias match {
3600+
// case tpe if tpe.baseClasses.contains(defn.PolyFunctionClass) =>
3601+
// attachEvidenceParams(tpe, params, span)
3602+
// case tpe: MethodType =>
3603+
// tpe.derivedLambdaType(tpe.paramNames, tpe.paramInfos, pushDownDeferredEvidenceParams(tpe.resultType, params, span))
3604+
// case tpe @ AppliedType(tycon, args) if defn.isFunctionType(tpe) && args.size > 1 =>
3605+
// tpe.derivedAppliedType(tycon, args.init :+ pushDownDeferredEvidenceParams(args.last, params, span))
3606+
// case tpe =>
3607+
// attachEvidenceParams(tpe, params, span)
3608+
// }
3609+
3610+
// /** (params) ?=> tpe */
3611+
// private def attachEvidenceParams(tpe: Type, params: List[untpd.ValDef], span: Span)(using Context): Type =
3612+
// val paramNames = params.map(_.name)
3613+
// val paramTpts = params.map(_.tpt)
3614+
// val paramsErased = params.map(_.mods.flags.is(Erased))
3615+
// val ctxFunction = desugar.makeContextualFunction(paramTpts, paramNames, untpd.TypedSplice(TypeTree(tpe.dealias)), paramsErased).withSpan(span)
3616+
// typed(ctxFunction).tpe
3617+
3618+
// /** If the tree has a `PolyFunctionApply` attachment, add the deferred
3619+
// * evidence parameters as the last argument list before the result type or a next poly type.
3620+
// * This follows aliases, so the following two types will be expanded to (up to the
3621+
// * context bound encoding):
3622+
// * type CmpWeak[X] = X => Boolean
3623+
// * type Comparer2Weak = [X: Ord] => X => CmpWeak[X]
3624+
// * ===>
3625+
// * type CmpWeak[X] = X => Boolean type Comparer2Weak = [X] => X => X ?=>
3626+
// * Ord[X] => Boolean
3627+
// */
3628+
// private def addDeferredEvidenceParams(tree: Tree, pt: Type)(using Context): (Tree, Type) = {
3629+
// tree.getAttachment(desugar.PolyFunctionApply) match
3630+
// case Some(params) if params.nonEmpty =>
3631+
// tree.putAttachment(desugar.PolyFunctionApply, Nil)
3632+
// val tpe = pushDownDeferredEvidenceParams(tree.tpe, params, tree.span)
3633+
// TypeTree(tpe).withSpan(tree.span) -> tpe
3634+
// case Some(params) =>
3635+
// tree -> pt
3636+
// case _ => tree -> pt
3637+
// }
36373638

36383639
/** Interpolate and simplify the type of the given tree. */
36393640
protected def simplify(tree: Tree, pt: Type, locked: TypeVars)(using Context): Tree =
3640-
val (tree1, pt1) = addDeferredEvidenceParams(tree, pt)
3641-
if !tree1.denot.isOverloaded then // for overloaded trees: resolve overloading before simplifying
3642-
if !tree1.tpe.widen.isInstanceOf[MethodOrPoly] // wait with simplifying until method is fully applied
3643-
|| tree1.isDef // ... unless tree is a definition
3641+
// val (tree1, pt1) = addDeferredEvidenceParams(tree, pt)
3642+
if !tree.denot.isOverloaded then // for overloaded trees: resolve overloading before simplifying
3643+
if !tree.tpe.widen.isInstanceOf[MethodOrPoly] // wait with simplifying until method is fully applied
3644+
|| tree.isDef // ... unless tree is a definition
36443645
then
3645-
interpolateTypeVars(tree1, pt1, locked)
3646-
val simplified = tree1.tpe.simplified
3647-
if !MatchType.thatReducesUsingGadt(tree1.tpe) then // needs a GADT cast. i15743
3646+
interpolateTypeVars(tree, pt, locked)
3647+
val simplified = tree.tpe.simplified
3648+
if !MatchType.thatReducesUsingGadt(tree.tpe) then // needs a GADT cast. i15743
36483649
tree.overwriteType(simplified)
3649-
tree1
3650+
tree
36503651

36513652
protected def makeContextualFunction(tree: untpd.Tree, pt: Type)(using Context): Tree = {
36523653
val defn.FunctionOf(formals, _, true) = pt.dropDependentRefinement: @unchecked

tests/pos/contextbounds-for-poly-functions.scala

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import scala.language.future
33

44
trait Ord[X]:
55
def compare(x: X, y: X): Int
6+
type T
67

78
trait Show[X]:
89
def show(x: X): String
@@ -11,6 +12,8 @@ val less0: [X: Ord] => (X, X) => Boolean = ???
1112

1213
val less1 = [X: Ord] => (x: X, y: X) => summon[Ord[X]].compare(x, y) < 0
1314

15+
type PolyTest1 = [X] => X => Ord[X] ?=> Boolean
16+
1417
val less1_type_test: [X: Ord] => (X, X) => Boolean =
1518
[X: Ord] => (x: X, y: X) => summon[Ord[X]].compare(x, y) < 0
1619

@@ -34,12 +37,12 @@ val lessCmp3_1: Cmp3 = [X: Ord as ord] => (x: X) => (y: X) => (z: X) => ord.comp
3437
// type Comparer2 = [X: Ord] => Cmp[X]
3538
// val less4: Comparer2 = [X: Ord] => (x: X, y: X) => summon[Ord[X]].compare(x, y) < 0
3639

37-
type CmpWeak[X] = X => Boolean
38-
type Comparer2Weak = [X: Ord] => X => CmpWeak[X]
39-
val less4_0: [X: Ord] => X => X => Boolean =
40-
[X: Ord] => (x: X) => (y: X) => summon[Ord[X]].compare(x, y) < 0
41-
val less4_1: Comparer2Weak =
42-
[X: Ord] => (x: X) => (y: X) => summon[Ord[X]].compare(x, y) < 0
40+
// type CmpWeak[X] = X => Boolean
41+
// type Comparer2Weak = [X: Ord] => X => CmpWeak[X]
42+
// val less4_0: [X: Ord] => X => X => Boolean =
43+
// [X: Ord] => (x: X) => (y: X) => summon[Ord[X]].compare(x, y) < 0
44+
// val less4_1: Comparer2Weak =
45+
// [X: Ord] => (x: X) => (y: X) => summon[Ord[X]].compare(x, y) < 0
4346

4447
val less5 = [X: [X] =>> Ord[X]] => (x: X, y: X) => summon[Ord[X]].compare(x, y) < 0
4548

@@ -65,3 +68,21 @@ val less9 = [X: {Ord as ord, Show as show}] => (x: X, y: X) => ord.compare(x, y)
6568

6669
val less9_type_test: [X: {Ord as ord, Show as show}] => (X, X) => Boolean =
6770
[X: {Ord as ord, Show as show}] => (x: X, y: X) => ord.compare(x, y) < 0
71+
72+
type CmpNested = [X: Ord] => X => [Y: Ord] => Y => Boolean
73+
val less10: CmpNested = [X: Ord] => (x: X) => [Y: Ord] => (y: Y) => true
74+
val less10Explicit: CmpNested = [X] => (x: X) => (ordx: Ord[X]) ?=> [Y] => (y: Y) => (ordy: Ord[Y]) ?=> true
75+
76+
// type CmpAlias[X] = X => Boolean
77+
// type CmpNestedAliased = [X: Ord] => X => [Y] => Y => CmpAlias[Y]
78+
79+
// val less11: CmpNestedAliased = [X: Ord] => (x: X) => [Y] => (y: Y) => (y1: Y) => true
80+
// val less11Explicit: CmpNestedAliased = [X] => (x: X) => (ordx: Ord[X]) ?=> [Y] => (y: Y) => (y1: Y) => true
81+
82+
val notationalExample: [X: Ord] => X => [Y: Ord] => Y => Int =
83+
[X] => (x: X) => (ordx: Ord[X]) ?=> [Y] => (y: Y) => (ordy: Ord[Y]) ?=> 1
84+
85+
val namedConstraintRef = [X: {Ord as ord}] => (x: ord.T) => x
86+
type DependentCmp = [X: {Ord as ord}] => ord.T => Boolean
87+
type DependentCmp1 = [X: {Ord as ord}] => (ord.T, Int) => ord.T => Boolean
88+
val dependentCmp: DependentCmp = [X: {Ord as ord}] => (x: ord.T) => true

0 commit comments

Comments
 (0)