Skip to content

Commit 9cd35cb

Browse files
committed
Use PolyFunction instead of ErasedFunction
We generalize the meaning of `PolyFunction` to mean any kind of refined lambda encoding. These refinements support any type with the following shape as a lambda type: ```scala PolyFunction { def apply[[T1, ..., Tn]]([given] [erased] x1: X1, ..., [erased] xn: Xn): R } ```
1 parent 182331b commit 9cd35cb

File tree

23 files changed

+58
-97
lines changed

23 files changed

+58
-97
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
954954
def isStructuralTermSelectOrApply(tree: Tree)(using Context): Boolean = {
955955
def isStructuralTermSelect(tree: Select) =
956956
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match
957-
case defn.PolyOrErasedFunctionOf(_) =>
957+
case defn.PolyFunctionOf(_) =>
958958
false
959959
case RefinedType(parent, rname, rinfo) =>
960960
rname == tree.name || hasRefinement(parent)

compiler/src/dotty/tools/dotc/cc/Setup.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ extends tpd.TreeTraverser:
197197
val mt = ContextualMethodType(paramName :: Nil)(
198198
_ => paramType :: Nil,
199199
mt => if isLast then res else expandThrowsAlias(res, mt :: encl))
200-
val fntpe = RefinedType(defn.ErasedFunctionClass.typeRef, nme.apply, mt)
200+
val fntpe = RefinedType(defn.PolyFunctionClass.typeRef, nme.apply, mt)
201201
if !encl.isEmpty && isLast then
202202
val cs = CaptureSet(encl.map(_.paramRefs.head)*)
203203
CapturingType(fntpe, cs, boxed = false)

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 8 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,12 +1112,12 @@ class Definitions {
11121112
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false)(using Context): Type =
11131113
val mt = MethodType.companion(isContextual, false)(args, resultType)
11141114
if mt.hasErasedParams then
1115-
RefinedType(ErasedFunctionClass.typeRef, nme.apply, mt)
1115+
RefinedType(PolyFunctionClass.typeRef, nme.apply, mt)
11161116
else
11171117
FunctionType(args.length, isContextual).appliedTo(args ::: resultType :: Nil)
11181118
def unapply(ft: Type)(using Context): Option[(List[Type], Type, Boolean)] = {
11191119
ft.dealias match
1120-
case ErasedFunctionOf(mt) =>
1120+
case PolyFunctionOf(mt: MethodType) =>
11211121
Some(mt.paramInfos, mt.resType, mt.isContextualMethod)
11221122
case dft =>
11231123
val tsym = dft.typeSymbol
@@ -1129,38 +1129,14 @@ class Definitions {
11291129
}
11301130
}
11311131

1132-
object PolyOrErasedFunctionOf {
1133-
/** Matches a refined `PolyFunction` or `ErasedFunction` type and extracts the apply info.
1134-
*
1135-
* Pattern: `(PolyFunction | ErasedFunction) { def apply: $mt }`
1136-
*/
1137-
def unapply(ft: Type)(using Context): Option[MethodicType] = ft.dealias match
1138-
case RefinedType(parent, nme.apply, mt: MethodicType)
1139-
if parent.derivesFrom(defn.PolyFunctionClass) || parent.derivesFrom(defn.ErasedFunctionClass) =>
1140-
Some(mt)
1141-
case _ => None
1142-
}
1143-
11441132
object PolyFunctionOf {
11451133
/** Matches a refined `PolyFunction` type and extracts the apply info.
11461134
*
1147-
* Pattern: `PolyFunction { def apply: $pt }`
1135+
* Pattern: `PolyFunction { def apply: $mt }`
11481136
*/
1149-
def unapply(ft: Type)(using Context): Option[PolyType] = ft.dealias match
1150-
case RefinedType(parent, nme.apply, pt: PolyType)
1137+
def unapply(ft: Type)(using Context): Option[MethodicType] = ft.dealias match
1138+
case RefinedType(parent, nme.apply, mt: MethodicType)
11511139
if parent.derivesFrom(defn.PolyFunctionClass) =>
1152-
Some(pt)
1153-
case _ => None
1154-
}
1155-
1156-
object ErasedFunctionOf {
1157-
/** Matches a refined `ErasedFunction` type and extracts the apply info.
1158-
*
1159-
* Pattern: `ErasedFunction { def apply: $mt }`
1160-
*/
1161-
def unapply(ft: Type)(using Context): Option[MethodType] = ft.dealias match
1162-
case RefinedType(parent, nme.apply, mt: MethodType)
1163-
if parent.derivesFrom(defn.ErasedFunctionClass) =>
11641140
Some(mt)
11651141
case _ => None
11661142
}
@@ -1514,9 +1490,6 @@ class Definitions {
15141490
lazy val PolyFunctionClass = requiredClass("scala.PolyFunction")
15151491
def PolyFunctionType = PolyFunctionClass.typeRef
15161492

1517-
lazy val ErasedFunctionClass = requiredClass("scala.runtime.ErasedFunction")
1518-
def ErasedFunctionType = ErasedFunctionClass.typeRef
1519-
15201493
/** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */
15211494
def scalaClassName(cls: Symbol)(using Context): TypeName = cls.denot match
15221495
case clsd: ClassDenotation if clsd.owner eq ScalaPackageClass =>
@@ -1579,8 +1552,6 @@ class Definitions {
15791552
/** Is a synthetic function class
15801553
* - FunctionN for N > 22
15811554
* - ContextFunctionN for N >= 0
1582-
* - ErasedFunctionN for N > 0
1583-
* - ErasedContextFunctionN for N > 0
15841555
*/
15851556
def isSyntheticFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isSyntheticFunction
15861557

@@ -1596,8 +1567,6 @@ class Definitions {
15961567
* - FunctionN for 22 > N >= 0 remains as FunctionN
15971568
* - ContextFunctionN for N > 22 becomes FunctionXXL
15981569
* - ContextFunctionN for N <= 22 becomes FunctionN
1599-
* - ErasedFunctionN becomes Function0
1600-
* - ImplicitErasedFunctionN becomes Function0
16011570
* - anything else becomes a NoType
16021571
*/
16031572
def functionTypeErasure(cls: Symbol): Type =
@@ -1756,13 +1725,11 @@ class Definitions {
17561725
/** Returns whether `tp` is an instance or a refined instance of:
17571726
* - scala.FunctionN
17581727
* - scala.ContextFunctionN
1759-
* - ErasedFunction
17601728
* - PolyFunction
17611729
*/
17621730
def isFunctionType(tp: Type)(using Context): Boolean =
17631731
isFunctionNType(tp)
17641732
|| tp.derivesFrom(defn.PolyFunctionClass) // TODO check for refinement?
1765-
|| tp.derivesFrom(defn.ErasedFunctionClass) // TODO check for refinement?
17661733

17671734
private def withSpecMethods(cls: ClassSymbol, bases: List[Name], paramTypes: Set[TypeRef]) =
17681735
if !ctx.settings.Yscala2Stdlib.value then
@@ -1866,7 +1833,7 @@ class Definitions {
18661833
tp.stripTypeVar.dealias match
18671834
case tp1: TypeParamRef if ctx.typerState.constraint.contains(tp1) =>
18681835
asContextFunctionType(TypeComparer.bounds(tp1).hiBound)
1869-
case tp1 @ ErasedFunctionOf(mt) if mt.isContextualMethod =>
1836+
case tp1 @ PolyFunctionOf(mt: MethodType) if mt.isContextualMethod =>
18701837
tp1
18711838
case tp1 =>
18721839
if tp1.typeSymbol.name.isContextFunction && isFunctionNType(tp1) then tp1
@@ -1886,21 +1853,14 @@ class Definitions {
18861853
atPhase(erasurePhase)(unapply(tp))
18871854
else
18881855
asContextFunctionType(tp) match
1889-
case ErasedFunctionOf(mt) =>
1856+
case PolyFunctionOf(mt: MethodType) =>
18901857
Some((mt.paramInfos, mt.resType, mt.erasedParams))
18911858
case tp1 if tp1.exists =>
18921859
val args = tp1.functionArgInfos
1893-
val erasedParams = erasedFunctionParameters(tp1)
1860+
val erasedParams = List.fill(functionArity(tp1)) { false }
18941861
Some((args.init, args.last, erasedParams))
18951862
case _ => None
18961863

1897-
/* Returns a list of erased booleans marking whether parameters are erased, for a function type. */
1898-
def erasedFunctionParameters(tp: Type)(using Context): List[Boolean] = tp.dealias match {
1899-
case ErasedFunctionOf(mt) => mt.erasedParams
1900-
case tp if isFunctionNType(tp) => List.fill(functionArity(tp)) { false }
1901-
case _ => Nil
1902-
}
1903-
19041864
/** A whitelist of Scala-2 classes that are known to be pure */
19051865
def isAssuredNoInits(sym: Symbol): Boolean =
19061866
(sym `eq` SomeClass) || isTupleClass(sym)

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ object StdNames {
3434
inline val MODULE_INSTANCE_FIELD = "MODULE$"
3535

3636
inline val Function = "Function"
37-
inline val ErasedFunction = "ErasedFunction"
3837
inline val ContextFunction = "ContextFunction"
3938
inline val ErasedContextFunction = "ErasedContextFunction"
4039
inline val AbstractFunction = "AbstractFunction"
@@ -214,7 +213,6 @@ object StdNames {
214213
final val Throwable: N = "Throwable"
215214
final val IOOBException: N = "IndexOutOfBoundsException"
216215
final val FunctionXXL: N = "FunctionXXL"
217-
final val ErasedFunction: N = "ErasedFunction"
218216

219217
final val Abs: N = "Abs"
220218
final val And: N = "&&"

compiler/src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,10 +506,10 @@ class TypeApplications(val self: Type) extends AnyVal {
506506
case _ => Nil
507507

508508
/** If this is an encoding of a function type, return its arguments, otherwise return Nil.
509-
* Handles `ErasedFunction`s and poly functions gracefully.
509+
* Handles poly functions gracefully.
510510
*/
511511
final def functionArgInfos(using Context): List[Type] = self.dealias match
512-
case defn.ErasedFunctionOf(mt) => (mt.paramInfos :+ mt.resultType)
512+
case defn.PolyFunctionOf(mt: MethodType) => (mt.paramInfos :+ mt.resultType)
513513
case _ => self.dropDependentRefinement.dealias.argInfos
514514

515515
/** Argument types where existential types in arguments are disallowed */

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
667667

668668
if defn.isFunctionType(tp2) then
669669
if tp2.derivesFrom(defn.PolyFunctionClass) then
670-
// TODO should we handle ErasedFunction is this same way?
671670
tp1.member(nme.apply).info match
672671
case info1: PolyType =>
673672
return isSubInfo(info1, tp2.refinedInfo)

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ object TypeErasure {
560560
case _ => false
561561
}
562562

563-
/** The erasure of `(PolyFunction | ErasedFunction) { def apply: $applyInfo }` */
563+
/** The erasure of `PolyFunction { def apply: $applyInfo }` */
564564
def eraseRefinedFunctionApply(applyInfo: Type)(using Context): Type =
565565
def functionType(info: Type): Type = info match {
566566
case info: PolyType =>
@@ -654,7 +654,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
654654
else SuperType(eThis, eSuper)
655655
case ExprType(rt) =>
656656
defn.FunctionType(0)
657-
case defn.PolyOrErasedFunctionOf(mt) =>
657+
case defn.PolyFunctionOf(mt) =>
658658
eraseRefinedFunctionApply(mt)
659659
case tp: TypeVar if !tp.isInstantiated =>
660660
assert(inSigName, i"Cannot erase uninstantiated type variable $tp")
@@ -936,7 +936,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
936936
sigName(defn.FunctionOf(Nil, rt))
937937
case tp: TypeVar if !tp.isInstantiated =>
938938
tpnme.Uninstantiated
939-
case tp @ defn.PolyOrErasedFunctionOf(_) =>
939+
case tp @ defn.PolyFunctionOf(_) =>
940940
// we need this case rather than falling through to the default
941941
// because RefinedTypes <: TypeProxy and it would be caught by
942942
// the case immediately below

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1886,7 +1886,7 @@ object Types {
18861886
formals1 mapConserve (_.translateFromRepeated(toArray = isJava)),
18871887
result1, isContextual)
18881888
if mt.hasErasedParams then
1889-
RefinedType(defn.ErasedFunctionType, nme.apply, mt)
1889+
RefinedType(defn.PolyFunctionType, nme.apply, mt)
18901890
else if alwaysDependent || mt.isResultDependent then
18911891
RefinedType(nonDependentFunType, nme.apply, mt)
18921892
else nonDependentFunType

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ object Erasure {
679679
// Instead, we manually lookup the type of `apply` in the qualifier.
680680
inContext(preErasureCtx) {
681681
val qualTp = tree.qualifier.typeOpt.widen
682-
if qualTp.derivesFrom(defn.PolyFunctionClass) || qualTp.derivesFrom(defn.ErasedFunctionClass) then
682+
if qualTp.derivesFrom(defn.PolyFunctionClass) then
683683
eraseRefinedFunctionApply(qualTp.select(nme.apply).widen).classSymbol
684684
else
685685
NoSymbol

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -446,11 +446,8 @@ object TreeChecker {
446446
assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase)
447447
val tpe = tree.typeOpt
448448

449-
// PolyFunction and ErasedFunction apply methods stay structural until Erasure
450-
val isRefinedFunctionApply = (tree.name eq nme.apply) && {
451-
val qualTpe = tree.qualifier.typeOpt
452-
qualTpe.derivesFrom(defn.PolyFunctionClass) || qualTpe.derivesFrom(defn.ErasedFunctionClass)
453-
}
449+
// PolyFunction apply method stay structural until Erasure
450+
val isRefinedFunctionApply = (tree.name eq nme.apply) && tree.qualifier.typeOpt.derivesFrom(defn.PolyFunctionClass)
454451

455452
// Outer selects are pickled specially so don't require a symbol
456453
val isOuterSelect = tree.name.is(OuterSelectName)

0 commit comments

Comments
 (0)