Skip to content

Commit 7755e3b

Browse files
committed
Cleanup context bounds for poly functions implementation, make the implementation consistent with addEvidenceParams
1 parent dfa9240 commit 7755e3b

File tree

3 files changed

+26
-118
lines changed

3 files changed

+26
-118
lines changed

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

+16-63
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,9 @@ object desugar {
5353
*/
5454
val ContextBoundParam: Property.Key[Unit] = Property.StickyKey()
5555

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
56+
/** Marks a poly fcuntion apply method, so that we can handle adding evidence parameters to them in a special way
6257
*/
63-
val PolyFunctionApply: Property.Key[List[ValDef]] = Property.StickyKey()
58+
val PolyFunctionApply: Property.Key[Unit] = Property.StickyKey()
6459

6560
/** What static check should be applied to a Match? */
6661
enum MatchCheck {
@@ -520,61 +515,28 @@ object desugar {
520515
case Nil =>
521516
Nil -> (params :: Nil)
522517

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-
539518
def functionsOf(paramss: List[ParamClause], rhs: Tree): Tree = paramss match
540519
case Nil => rhs
541520
case ValDefs(head @ (fst :: _)) :: rest if fst.mods.isOneOf(GivenOrImplicit) =>
542521
val paramTpts = params.map(_.tpt)
543522
val paramNames = params.map(_.name)
544523
val paramsErased = params.map(_.mods.flags.is(Erased))
545524
makeContextualFunction(paramTpts, paramNames, functionsOf(rest, rhs), paramsErased).withSpan(rhs.span)
546-
case head :: rest =>
525+
case ValDefs(head) :: rest =>
547526
Function(head, functionsOf(rest, rhs))
527+
case head :: _ =>
528+
assert(false, i"unexpected type parameters when adding evidence parameters to $meth")
529+
EmptyTree
548530

549531
if meth.hasAttachment(PolyFunctionApply) then
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))
532+
meth.removeAttachment(PolyFunctionApply)
533+
// for PolyFunctions we are limited to a single term param list, so we reuse the recur logic to compute the new parameter lists
534+
// and then we add the other parameter lists as function types to the return type
535+
val (paramsFst, paramsSnd) = recur(meth.paramss)
536+
if ctx.mode.is(Mode.Type) then
537+
cpy.DefDef(meth)(paramss = paramsFst, tpt = functionsOf(paramsSnd, meth.tpt))
538+
else
539+
cpy.DefDef(meth)(paramss = paramsFst, rhs = functionsOf(paramsSnd, meth.rhs))
578540
else
579541
val (paramsFst, paramsSnd) = recur(meth.paramss)
580542
cpy.DefDef(meth)(paramss = paramsFst ++ paramsSnd)
@@ -1293,7 +1255,7 @@ object desugar {
12931255
/** Desugar [T_1, ..., T_M] => (P_1, ..., P_N) => R
12941256
* Into scala.PolyFunction { def apply[T_1, ..., T_M](x$1: P_1, ..., x$N: P_N): R }
12951257
*/
1296-
def makePolyFunctionType(tree: PolyFunction)(using Context): RefinedTypeTree = tree match
1258+
def makePolyFunctionType(tree: PolyFunction)(using Context): RefinedTypeTree = (tree: @unchecked) match
12971259
case PolyFunction(tparams: List[untpd.TypeDef] @unchecked, fun @ untpd.Function(vparamTypes, res)) =>
12981260
val paramFlags = fun match
12991261
case fun: FunctionWithMods =>
@@ -1311,20 +1273,11 @@ object desugar {
13111273
case ((p, paramFlags), n) => makeSyntheticParameter(n + 1, p).withAddedFlags(paramFlags)
13121274
}.toList
13131275

1314-
vparams.foreach(p => println(i" $p, ${p.mods.flags.flagsString}"))
13151276
RefinedTypeTree(ref(defn.PolyFunctionType), List(
13161277
DefDef(nme.apply, tparams :: vparams :: Nil, res, EmptyTree)
13171278
.withFlags(Synthetic)
1318-
.withAttachment(PolyFunctionApply, List.empty)
1319-
)).withSpan(tree.span)
1320-
.withAttachment(PolyFunctionApply, tree.attachmentOrElse(PolyFunctionApply, List.empty))
1321-
case PolyFunction(tparams: List[untpd.TypeDef] @unchecked, res) =>
1322-
RefinedTypeTree(ref(defn.PolyFunctionType), List(
1323-
DefDef(nme.apply, tparams :: Nil, res, EmptyTree)
1324-
.withFlags(Synthetic)
1325-
.withAttachment(PolyFunctionApply, List.empty)
1279+
.withAttachment(PolyFunctionApply, ())
13261280
)).withSpan(tree.span)
1327-
.withAttachment(PolyFunctionApply, tree.attachmentOrElse(PolyFunctionApply, List.empty))
13281281
end makePolyFunctionType
13291282

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

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

-45
Original file line numberDiff line numberDiff line change
@@ -3592,53 +3592,8 @@ 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 =
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-
// }
3638-
36393595
/** Interpolate and simplify the type of the given tree. */
36403596
protected def simplify(tree: Tree, pt: Type, locked: TypeVars)(using Context): Tree =
3641-
// val (tree1, pt1) = addDeferredEvidenceParams(tree, pt)
36423597
if !tree.denot.isOverloaded then // for overloaded trees: resolve overloading before simplifying
36433598
if !tree.tpe.widen.isInstanceOf[MethodOrPoly] // wait with simplifying until method is fully applied
36443599
|| tree.isDef // ... unless tree is a definition

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

+10-10
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ val lessCmp3_1: Cmp3 = [X: Ord as ord] => (x: X) => (y: X) => (z: X) => ord.comp
3737
// type Comparer2 = [X: Ord] => Cmp[X]
3838
// val less4: Comparer2 = [X: Ord] => (x: X, y: X) => summon[Ord[X]].compare(x, y) < 0
3939

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
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
4646

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

@@ -73,11 +73,11 @@ type CmpNested = [X: Ord] => X => [Y: Ord] => Y => Boolean
7373
val less10: CmpNested = [X: Ord] => (x: X) => [Y: Ord] => (y: Y) => true
7474
val less10Explicit: CmpNested = [X] => (x: X) => (ordx: Ord[X]) ?=> [Y] => (y: Y) => (ordy: Ord[Y]) ?=> true
7575

76-
// type CmpAlias[X] = X => Boolean
77-
// type CmpNestedAliased = [X: Ord] => X => [Y] => Y => CmpAlias[Y]
76+
type CmpAlias[X] = X => Boolean
77+
type CmpNestedAliased = [X: Ord] => X => [Y] => Y => CmpAlias[Y]
7878

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
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
8181

8282
val notationalExample: [X: Ord] => X => [Y: Ord] => Y => Int =
8383
[X] => (x: X) => (ordx: Ord[X]) ?=> [Y] => (y: Y) => (ordy: Ord[Y]) ?=> 1

0 commit comments

Comments
 (0)