Skip to content

Commit f3b50dd

Browse files
committed
Implement individual erased parameters
Breaking change for erasedDefinitions: this effectively makes the current `erased` marker in parameter list apply to only the first parameter. def f(erased a: int, b: int) should now be written as def f(erased a: int, erased b: int) type Function1 = (x: Int, erased y: Int) => Int type Function2 = (Int, erased Int) => Int Use refined traits for erased functions - function types with erased parameters are now always `ErasedFunction` refined with the correct `apply` definition, for example: scala.ErasedFunction { def apply(x1: Int, erased x2: Int): Int } where ErasedFunctions is an @experimental empty trait.
1 parent 4a11252 commit f3b50dd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+465
-245
lines changed

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

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,10 +1496,10 @@ object desugar {
14961496
case vd: ValDef => vd
14971497
}
14981498

1499-
def makeContextualFunction(formals: List[Tree], body: Tree, isErased: Boolean)(using Context): Function = {
1500-
val mods = if (isErased) Given | Erased else Given
1499+
def makeContextualFunction(formals: List[Tree], body: Tree, erasedParams: List[Boolean])(using Context): Function = {
1500+
val mods = Given
15011501
val params = makeImplicitParameters(formals, mods)
1502-
FunctionWithMods(params, body, Modifiers(mods))
1502+
FunctionWithMods(params, body, Modifiers(mods), erasedParams)
15031503
}
15041504

15051505
private def derivedValDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(using Context) = {
@@ -1832,6 +1832,7 @@ object desugar {
18321832
cpy.ByNameTypeTree(parent)(annotate(tpnme.retainsByName, restpt))
18331833
case _ =>
18341834
annotate(tpnme.retains, parent)
1835+
case f: FunctionWithMods if f.erasedParams.contains(true) => makeFunctionWithValDefs(f, pt)
18351836
}
18361837
desugared.withSpan(tree.span)
18371838
}
@@ -1907,6 +1908,28 @@ object desugar {
19071908
TypeDef(tpnme.REFINE_CLASS, impl).withFlags(Trait)
19081909
}
19091910

1911+
/** Ensure the given function tree use only ValDefs for parameters.
1912+
* For example,
1913+
* FunctionWithMods(List(TypeTree(A), TypeTree(B)), body, mods, erasedParams)
1914+
* gets converted to
1915+
* FunctionWithMods(List(ValDef(x$1, A), ValDef(x$2, B)), body, mods, erasedParams)
1916+
*/
1917+
def makeFunctionWithValDefs(tree: Function, pt: Type)(using Context): Function = {
1918+
val Function(args, result) = tree
1919+
args match {
1920+
case (_ : ValDef) :: _ => tree // ValDef case can be easily handled
1921+
case _ if !ctx.mode.is(Mode.Type) => tree
1922+
case _ =>
1923+
val applyVParams = args.zipWithIndex.map {
1924+
case (p, n) => makeSyntheticParameter(n + 1, p)
1925+
}
1926+
tree match
1927+
case tree: FunctionWithMods =>
1928+
untpd.FunctionWithMods(applyVParams, tree.body, tree.mods, tree.erasedParams)
1929+
case _ => untpd.Function(applyVParams, result)
1930+
}
1931+
}
1932+
19101933
/** Returns list of all pattern variables, possibly with their types,
19111934
* without duplicates
19121935
*/

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,9 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
908908
&& tree.isTerm
909909
&& {
910910
val qualType = tree.qualifier.tpe
911-
hasRefinement(qualType) && !qualType.derivesFrom(defn.PolyFunctionClass)
911+
hasRefinement(qualType) &&
912+
!qualType.derivesFrom(defn.PolyFunctionClass) &&
913+
!defn.isErasedFunctionType(qualType)
912914
}
913915
def loop(tree: Tree): Boolean = tree match
914916
case TypeApply(fun, _) =>

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,12 +254,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
254254
// If `isParamDependent == false`, the value of `previousParamRefs` is not used.
255255
if isParamDependent then mutable.ListBuffer[TermRef]() else (null: ListBuffer[TermRef] | Null).uncheckedNN
256256

257-
def valueParam(name: TermName, origInfo: Type): TermSymbol =
257+
def valueParam(name: TermName, origInfo: Type, isErased: Boolean): TermSymbol =
258258
val maybeImplicit =
259259
if tp.isContextualMethod then Given
260260
else if tp.isImplicitMethod then Implicit
261261
else EmptyFlags
262-
val maybeErased = if tp.isErasedMethod then Erased else EmptyFlags
262+
val maybeErased = if isErased then Erased else EmptyFlags
263263

264264
def makeSym(info: Type) = newSymbol(sym, name, TermParam | maybeImplicit | maybeErased, info, coord = sym.coord)
265265

@@ -277,7 +277,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
277277
assert(vparams.hasSameLengthAs(tp.paramNames) && vparams.head.isTerm)
278278
(vparams.asInstanceOf[List[TermSymbol]], remaining1)
279279
case nil =>
280-
(tp.paramNames.lazyZip(tp.paramInfos).map(valueParam), Nil)
280+
(tp.paramNames.lazyZip(tp.paramInfos).lazyZip(tp.erasedParams).map(valueParam), Nil)
281281
val (rtp, paramss) = recur(tp.instantiate(vparams.map(_.termRef)), remaining1)
282282
(rtp, vparams :: paramss)
283283
case _ =>
@@ -1130,10 +1130,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11301130

11311131
def etaExpandCFT(using Context): Tree =
11321132
def expand(target: Tree, tp: Type)(using Context): Tree = tp match
1133-
case defn.ContextFunctionType(argTypes, resType, isErased) =>
1133+
case defn.ContextFunctionType(argTypes, resType, erasedParams) =>
11341134
val anonFun = newAnonFun(
11351135
ctx.owner,
1136-
MethodType.companion(isContextual = true, isErased = isErased)(argTypes, resType),
1136+
MethodType.companion(isContextual = true, erasedParams = erasedParams)(argTypes, resType),
11371137
coord = ctx.owner.coord)
11381138
def lambdaBody(refss: List[List[Tree]]) =
11391139
expand(target.select(nme.apply).appliedToArgss(refss), resType)(

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,10 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
7676
}
7777

7878
/** A function type or closure with `implicit`, `erased`, or `given` modifiers */
79-
class FunctionWithMods(args: List[Tree], body: Tree, val mods: Modifiers)(implicit @constructorOnly src: SourceFile)
80-
extends Function(args, body)
79+
class FunctionWithMods(args: List[Tree], body: Tree, val mods: Modifiers, val erasedParams: List[Boolean])(implicit @constructorOnly src: SourceFile)
80+
extends Function(args, body) {
81+
assert(args.length == erasedParams.length)
82+
}
8183

8284
/** A polymorphic function type */
8385
case class PolyFunction(targs: List[Tree], body: Tree)(implicit @constructorOnly src: SourceFile) extends Tree {

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ extension (tp: Type)
146146
defn.FunctionType(
147147
fname.functionArity,
148148
isContextual = fname.isContextFunction,
149-
isErased = fname.isErasedFunction,
150149
isImpure = true).appliedTo(args)
151150
case _ =>
152151
tp

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,8 @@ class CheckCaptures extends Recheck, SymTransformer:
349349
mapArgUsing(_.forceBoxStatus(false))
350350
else if meth == defn.Caps_unsafeBoxFunArg then
351351
mapArgUsing {
352-
case defn.FunctionOf(paramtpe :: Nil, restpe, isContectual, isErased) =>
353-
defn.FunctionOf(paramtpe.forceBoxStatus(true) :: Nil, restpe, isContectual, isErased)
352+
case defn.FunctionOf(paramtpe :: Nil, restpe, isContectual, erasedParams) =>
353+
defn.FunctionOf(paramtpe.forceBoxStatus(true) :: Nil, restpe, isContectual, erasedParams)
354354
}
355355
else
356356
super.recheckApply(tree, pt) match
@@ -611,18 +611,18 @@ class CheckCaptures extends Recheck, SymTransformer:
611611
//println(i"check conforms $actual1 <<< $expected1")
612612
super.checkConformsExpr(actual1, expected1, tree)
613613

614-
private def toDepFun(args: List[Type], resultType: Type, isContextual: Boolean, isErased: Boolean)(using Context): Type =
615-
MethodType.companion(isContextual = isContextual, isErased = isErased)(args, resultType)
614+
private def toDepFun(args: List[Type], resultType: Type, isContextual: Boolean, erasedParams: List[Boolean])(using Context): Type =
615+
MethodType.companion(isContextual = isContextual, erasedParams = erasedParams)(args, resultType)
616616
.toFunctionType(isJava = false, alwaysDependent = true)
617617

618618
/** Turn `expected` into a dependent function when `actual` is dependent. */
619619
private def alignDependentFunction(expected: Type, actual: Type)(using Context): Type =
620620
def recur(expected: Type): Type = expected.dealias match
621621
case expected @ CapturingType(eparent, refs) =>
622622
CapturingType(recur(eparent), refs, boxed = expected.isBoxed)
623-
case expected @ defn.FunctionOf(args, resultType, isContextual, isErased)
623+
case expected @ defn.FunctionOf(args, resultType, isContextual, erasedParams)
624624
if defn.isNonRefinedFunction(expected) && defn.isFunctionType(actual) && !defn.isNonRefinedFunction(actual) =>
625-
val expected1 = toDepFun(args, resultType, isContextual, isErased)
625+
val expected1 = toDepFun(args, resultType, isContextual, erasedParams)
626626
expected1
627627
case _ =>
628628
expected

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ extends tpd.TreeTraverser:
3737
private def depFun(tycon: Type, argTypes: List[Type], resType: Type)(using Context): Type =
3838
MethodType.companion(
3939
isContextual = defn.isContextFunctionClass(tycon.classSymbol),
40-
isErased = defn.isErasedFunctionClass(tycon.classSymbol)
40+
erasedParams = defn.erasedFunctionParameters(tycon)
4141
)(argTypes, resType)
4242
.toFunctionType(isJava = false, alwaysDependent = true)
4343

@@ -259,7 +259,7 @@ extends tpd.TreeTraverser:
259259
private def expandThrowsAlias(tp: Type)(using Context) = tp match
260260
case AppliedType(tycon, res :: exc :: Nil) if tycon.typeSymbol == defn.throwsAlias =>
261261
// hard-coded expansion since $throws aliases in stdlib are defined with `?=>` rather than `?->`
262-
defn.FunctionOf(defn.CanThrowClass.typeRef.appliedTo(exc) :: Nil, res, isContextual = true, isErased = true)
262+
defn.FunctionOf(defn.CanThrowClass.typeRef.appliedTo(exc) :: Nil, res, isContextual = true, erasedParams = List(true))
263263
case _ => tp
264264

265265
private def expandThrowsAliases(using Context) = new TypeMap:

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

Lines changed: 55 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class Definitions {
8686
newPermanentClassSymbol(ScalaPackageClass, name, Artifact, completer).entered
8787
}
8888

89-
/** The trait FunctionN, ContextFunctionN, ErasedFunctionN or ErasedContextFunction, for some N
89+
/** The trait FunctionN and ContextFunctionN for some N
9090
* @param name The name of the trait to be created
9191
*
9292
* FunctionN traits follow this template:
@@ -104,21 +104,6 @@ class Definitions {
104104
* trait ContextFunctionN[-T0,...,-T{N-1}, +R] extends Object {
105105
* def apply(using $x0: T0, ..., $x{N_1}: T{N-1}): R
106106
* }
107-
*
108-
* ErasedFunctionN traits follow this template:
109-
*
110-
* trait ErasedFunctionN[-T0,...,-T{N-1}, +R] extends Object {
111-
* def apply(erased $x0: T0, ..., $x{N_1}: T{N-1}): R
112-
* }
113-
*
114-
* ErasedContextFunctionN traits follow this template:
115-
*
116-
* trait ErasedContextFunctionN[-T0,...,-T{N-1}, +R] extends Object {
117-
* def apply(using erased $x0: T0, ..., $x{N_1}: T{N-1}): R
118-
* }
119-
*
120-
* ErasedFunctionN and ErasedContextFunctionN erase to Function0.
121-
*
122107
* ImpureXYZFunctionN follow this template:
123108
*
124109
* type ImpureXYZFunctionN[-T0,...,-T{N-1}, +R] = {*} XYZFunctionN[T0,...,T{N-1}, R]
@@ -150,7 +135,7 @@ class Definitions {
150135
val methodType = MethodType.companion(
151136
isContextual = name.isContextFunction,
152137
isImplicit = false,
153-
isErased = name.isErasedFunction)
138+
erasedParams = List())
154139
decls.enter(newMethod(cls, nme.apply, methodType(argParamRefs, resParamRef), Deferred))
155140
denot.info =
156141
ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: Nil, decls)
@@ -1094,15 +1079,24 @@ class Definitions {
10941079
sym.owner.linkedClass.typeRef
10951080

10961081
object FunctionOf {
1097-
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false, isErased: Boolean = false)(using Context): Type =
1098-
FunctionType(args.length, isContextual, isErased).appliedTo(args ::: resultType :: Nil)
1099-
def unapply(ft: Type)(using Context): Option[(List[Type], Type, Boolean, Boolean)] = {
1100-
val tsym = ft.typeSymbol
1101-
if isFunctionClass(tsym) && ft.isRef(tsym) then
1102-
val targs = ft.dealias.argInfos
1103-
if (targs.isEmpty) None
1104-
else Some(targs.init, targs.last, tsym.name.isContextFunction, tsym.name.isErasedFunction)
1105-
else None
1082+
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false, erasedParams: List[Boolean] = List())(using Context): Type =
1083+
assert(erasedParams.size == 0 || args.size == erasedParams.size)
1084+
if erasedParams.contains(true) then
1085+
val mt = MethodType.companion(isContextual, false, erasedParams.padTo(args.size, false))(args, resultType)
1086+
RefinedType(ErasedFunctionType, nme.apply, mt)
1087+
else
1088+
FunctionType(args.length, isContextual).appliedTo(args ::: resultType :: Nil)
1089+
def unapply(ft: Type)(using Context): Option[(List[Type], Type, Boolean, List[Boolean])] = {
1090+
ft.dealias match
1091+
case RefinedType(parent, nme.apply, mt: MethodType) if isErasedFunctionType(parent) =>
1092+
Some(mt.paramInfos, mt.resType, mt.isContextualMethod, mt.erasedParams)
1093+
case _ =>
1094+
val tsym = ft.dealias.typeSymbol
1095+
if isFunctionSymbol(tsym) && ft.isRef(tsym) then
1096+
val targs = ft.dealias.argInfos
1097+
if (targs.isEmpty) None
1098+
else Some(targs.init, targs.last, tsym.name.isContextFunction, List.fill(targs.init.size) { false })
1099+
else None
11061100
}
11071101
}
11081102

@@ -1421,24 +1415,22 @@ class Definitions {
14211415
classRefs(n).nn
14221416
end FunType
14231417

1424-
private def funTypeIdx(isContextual: Boolean, isErased: Boolean, isImpure: Boolean): Int =
1418+
private def funTypeIdx(isContextual: Boolean, isImpure: Boolean): Int =
14251419
(if isContextual then 1 else 0)
1426-
+ (if isErased then 2 else 0)
1427-
+ (if isImpure then 4 else 0)
1420+
+ (if isImpure then 2 else 0)
14281421

14291422
private val funTypeArray: IArray[FunType] =
14301423
val arr = Array.ofDim[FunType](8)
14311424
val choices = List(false, true)
1432-
for contxt <- choices; erasd <- choices; impure <- choices do
1425+
for contxt <- choices; impure <- choices do
14331426
var str = "Function"
14341427
if contxt then str = "Context" + str
1435-
if erasd then str = "Erased" + str
14361428
if impure then str = "Impure" + str
1437-
arr(funTypeIdx(contxt, erasd, impure)) = FunType(str)
1429+
arr(funTypeIdx(contxt, impure)) = FunType(str)
14381430
IArray.unsafeFromArray(arr)
14391431

1440-
def FunctionSymbol(n: Int, isContextual: Boolean = false, isErased: Boolean = false, isImpure: Boolean = false)(using Context): Symbol =
1441-
funTypeArray(funTypeIdx(isContextual, isErased, isImpure))(n).symbol
1432+
def FunctionSymbol(n: Int, isContextual: Boolean = false, isImpure: Boolean = false)(using Context): Symbol =
1433+
funTypeArray(funTypeIdx(isContextual, isImpure))(n).symbol
14421434

14431435
@tu lazy val Function0_apply: Symbol = Function0.requiredMethod(nme.apply)
14441436
@tu lazy val ContextFunction0_apply: Symbol = ContextFunction0.requiredMethod(nme.apply)
@@ -1448,12 +1440,15 @@ class Definitions {
14481440
@tu lazy val Function2: Symbol = FunctionSymbol(2)
14491441
@tu lazy val ContextFunction0: Symbol = FunctionSymbol(0, isContextual = true)
14501442

1451-
def FunctionType(n: Int, isContextual: Boolean = false, isErased: Boolean = false, isImpure: Boolean = false)(using Context): TypeRef =
1452-
FunctionSymbol(n, isContextual && !ctx.erasedTypes, isErased, isImpure).typeRef
1443+
def FunctionType(n: Int, isContextual: Boolean = false, isImpure: Boolean = false)(using Context): TypeRef =
1444+
FunctionSymbol(n, isContextual && !ctx.erasedTypes, isImpure).typeRef
14531445

14541446
lazy val PolyFunctionClass = requiredClass("scala.PolyFunction")
14551447
def PolyFunctionType = PolyFunctionClass.typeRef
14561448

1449+
lazy val ErasedFunctionClass = requiredClass("scala.ErasedFunction")
1450+
def ErasedFunctionType = ErasedFunctionClass.typeRef
1451+
14571452
/** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */
14581453
def scalaClassName(cls: Symbol)(using Context): TypeName = cls.denot match
14591454
case clsd: ClassDenotation if clsd.owner eq ScalaPackageClass =>
@@ -1484,10 +1479,9 @@ class Definitions {
14841479

14851480
/** Is any function class where
14861481
* - FunctionXXL
1482+
* - ErasedFunction
14871483
* - FunctionN for N >= 0
14881484
* - ContextFunctionN for N >= 0
1489-
* - ErasedFunctionN for N > 0
1490-
* - ErasedContextFunctionN for N > 0
14911485
*/
14921486
def isFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isFunction
14931487

@@ -1506,12 +1500,6 @@ class Definitions {
15061500
*/
15071501
def isContextFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isContextFunction
15081502

1509-
/** Is an erased function class.
1510-
* - ErasedFunctionN for N > 0
1511-
* - ErasedContextFunctionN for N > 0
1512-
*/
1513-
def isErasedFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isErasedFunction
1514-
15151503
/** Is either FunctionXXL or a class that will be erased to FunctionXXL
15161504
* - FunctionXXL
15171505
* - FunctionN for N >= 22
@@ -1548,8 +1536,7 @@ class Definitions {
15481536
*/
15491537
def functionTypeErasure(cls: Symbol): Type =
15501538
val arity = scalaClassName(cls).functionArity
1551-
if cls.name.isErasedFunction then FunctionType(0)
1552-
else if arity > 22 then FunctionXXLClass.typeRef
1539+
if arity > 22 then FunctionXXLClass.typeRef
15531540
else if arity >= 0 then FunctionType(arity)
15541541
else NoType
15551542

@@ -1680,13 +1667,13 @@ class Definitions {
16801667
arity >= 0
16811668
&& isFunctionClass(sym)
16821669
&& tp.isRef(
1683-
FunctionType(arity, sym.name.isContextFunction, sym.name.isErasedFunction).typeSymbol,
1670+
FunctionType(arity, sym.name.isContextFunction).typeSymbol,
16841671
skipRefined = false)
16851672
end isNonRefinedFunction
16861673

16871674
/** Is `tp` a representation of a (possibly dependent) function type or an alias of such? */
16881675
def isFunctionType(tp: Type)(using Context): Boolean =
1689-
isNonRefinedFunction(tp.dropDependentRefinement)
1676+
isNonRefinedFunction(tp.dropDependentRefinement) || isErasedFunctionType(tp)
16901677

16911678
def isFunctionOrPolyType(tp: Type)(using Context): Boolean =
16921679
isFunctionType(tp) || (tp.typeSymbol eq defn.PolyFunctionClass)
@@ -1778,7 +1765,7 @@ class Definitions {
17781765
@tu lazy val FunctionSpecializedApplyNames: collection.Set[Name] =
17791766
Function0SpecializedApplyNames ++ Function1SpecializedApplyNames ++ Function2SpecializedApplyNames
17801767

1781-
def functionArity(tp: Type)(using Context): Int = tp.dropDependentRefinement.dealias.argInfos.length - 1
1768+
def functionArity(tp: Type)(using Context): Int = tp.functionArgInfos.length - 1
17821769

17831770
/** Return underlying context function type (i.e. instance of an ContextFunctionN class)
17841771
* or NoType if none exists. The following types are considered as underlying types:
@@ -1790,6 +1777,8 @@ class Definitions {
17901777
tp.stripTypeVar.dealias match
17911778
case tp1: TypeParamRef if ctx.typerState.constraint.contains(tp1) =>
17921779
asContextFunctionType(TypeComparer.bounds(tp1).hiBound)
1780+
case tp1 @ RefinedType(parent, nme.apply, mt: MethodType) if isErasedFunctionType(parent) && mt.isContextualMethod =>
1781+
tp1
17931782
case tp1 =>
17941783
if tp1.typeSymbol.name.isContextFunction && isFunctionType(tp1) then tp1
17951784
else NoType
@@ -1803,18 +1792,28 @@ class Definitions {
18031792
* types `As`, the result type `B` and a whether the type is an erased context function.
18041793
*/
18051794
object ContextFunctionType:
1806-
def unapply(tp: Type)(using Context): Option[(List[Type], Type, Boolean)] =
1795+
def unapply(tp: Type)(using Context): Option[(List[Type], Type, List[Boolean])] =
18071796
if ctx.erasedTypes then
18081797
atPhase(erasurePhase)(unapply(tp))
18091798
else
1810-
val tp1 = asContextFunctionType(tp)
1811-
if tp1.exists then
1812-
val args = tp1.dropDependentRefinement.argInfos
1813-
Some((args.init, args.last, tp1.typeSymbol.name.isErasedFunction))
1814-
else None
1799+
asContextFunctionType(tp) match
1800+
case RefinedType(parent, nme.apply, mt: MethodType) if isErasedFunctionType(parent) =>
1801+
Some((mt.paramInfos, mt.resType, mt.erasedParams))
1802+
case tp1 if tp1.exists =>
1803+
val args = tp1.functionArgInfos
1804+
val erasedParams = erasedFunctionParameters(tp1)
1805+
Some((args.init, args.last, erasedParams))
1806+
case _ => None
1807+
1808+
/* Returns a list of erased booleans marking whether parameters are erased, for a function type. */
1809+
def erasedFunctionParameters(tp: Type)(using Context): List[Boolean] = tp.dealias match {
1810+
case RefinedType(parent, nme.apply, mt: MethodType) => mt.erasedParams
1811+
case tp if isFunctionType(tp) => List.fill(functionArity(tp)) { false }
1812+
case _ => Nil
1813+
}
18151814

18161815
def isErasedFunctionType(tp: Type)(using Context): Boolean =
1817-
tp.dealias.typeSymbol.name.isErasedFunction && isFunctionType(tp)
1816+
tp.derivesFrom(defn.ErasedFunctionClass)
18181817

18191818
/** A whitelist of Scala-2 classes that are known to be pure */
18201819
def isAssuredNoInits(sym: Symbol): Boolean =

0 commit comments

Comments
 (0)