Skip to content

Commit 5479bd6

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 d99d9bf commit 5479bd6

Some content is hidden

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

43 files changed

+488
-254
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
@@ -952,7 +952,9 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
952952
&& tree.isTerm
953953
&& {
954954
val qualType = tree.qualifier.tpe
955-
hasRefinement(qualType) && !qualType.derivesFrom(defn.PolyFunctionClass)
955+
hasRefinement(qualType) &&
956+
!qualType.derivesFrom(defn.PolyFunctionClass) &&
957+
!defn.isErasedFunctionType(qualType)
956958
}
957959
def loop(tree: Tree): Boolean = tree match
958960
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
@@ -77,8 +77,10 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
7777
}
7878

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

8385
/** A polymorphic function type */
8486
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
@@ -336,8 +336,8 @@ class CheckCaptures extends Recheck, SymTransformer:
336336
mapArgUsing(_.forceBoxStatus(false))
337337
else if meth == defn.Caps_unsafeBoxFunArg then
338338
mapArgUsing {
339-
case defn.FunctionOf(paramtpe :: Nil, restpe, isContectual, isErased) =>
340-
defn.FunctionOf(paramtpe.forceBoxStatus(true) :: Nil, restpe, isContectual, isErased)
339+
case defn.FunctionOf(paramtpe :: Nil, restpe, isContectual, erasedParams) =>
340+
defn.FunctionOf(paramtpe.forceBoxStatus(true) :: Nil, restpe, isContectual, erasedParams)
341341
}
342342
else
343343
super.recheckApply(tree, pt) match
@@ -598,18 +598,18 @@ class CheckCaptures extends Recheck, SymTransformer:
598598
//println(i"check conforms $actual1 <<< $expected1")
599599
super.checkConformsExpr(actual1, expected1, tree)
600600

601-
private def toDepFun(args: List[Type], resultType: Type, isContextual: Boolean, isErased: Boolean)(using Context): Type =
602-
MethodType.companion(isContextual = isContextual, isErased = isErased)(args, resultType)
601+
private def toDepFun(args: List[Type], resultType: Type, isContextual: Boolean, erasedParams: List[Boolean])(using Context): Type =
602+
MethodType.companion(isContextual = isContextual, erasedParams = erasedParams)(args, resultType)
603603
.toFunctionType(isJava = false, alwaysDependent = true)
604604

605605
/** Turn `expected` into a dependent function when `actual` is dependent. */
606606
private def alignDependentFunction(expected: Type, actual: Type)(using Context): Type =
607607
def recur(expected: Type): Type = expected.dealias match
608608
case expected @ CapturingType(eparent, refs) =>
609609
CapturingType(recur(eparent), refs, boxed = expected.isBoxed)
610-
case expected @ defn.FunctionOf(args, resultType, isContextual, isErased)
610+
case expected @ defn.FunctionOf(args, resultType, isContextual, erasedParams)
611611
if defn.isNonRefinedFunction(expected) && defn.isFunctionType(actual) && !defn.isNonRefinedFunction(actual) =>
612-
val expected1 = toDepFun(args, resultType, isContextual, isErased)
612+
val expected1 = toDepFun(args, resultType, isContextual, erasedParams)
613613
expected1
614614
case _ =>
615615
expected

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

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

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

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

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

Lines changed: 54 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)
@@ -1095,15 +1080,24 @@ class Definitions {
10951080
sym.owner.linkedClass.typeRef
10961081

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

@@ -1422,24 +1416,22 @@ class Definitions {
14221416
classRefs(n).nn
14231417
end FunType
14241418

1425-
private def funTypeIdx(isContextual: Boolean, isErased: Boolean, isImpure: Boolean): Int =
1419+
private def funTypeIdx(isContextual: Boolean, isImpure: Boolean): Int =
14261420
(if isContextual then 1 else 0)
1427-
+ (if isErased then 2 else 0)
1428-
+ (if isImpure then 4 else 0)
1421+
+ (if isImpure then 2 else 0)
14291422

14301423
private val funTypeArray: IArray[FunType] =
14311424
val arr = Array.ofDim[FunType](8)
14321425
val choices = List(false, true)
1433-
for contxt <- choices; erasd <- choices; impure <- choices do
1426+
for contxt <- choices; impure <- choices do
14341427
var str = "Function"
14351428
if contxt then str = "Context" + str
1436-
if erasd then str = "Erased" + str
14371429
if impure then str = "Impure" + str
1438-
arr(funTypeIdx(contxt, erasd, impure)) = FunType(str)
1430+
arr(funTypeIdx(contxt, impure)) = FunType(str)
14391431
IArray.unsafeFromArray(arr)
14401432

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

14441436
@tu lazy val Function0_apply: Symbol = Function0.requiredMethod(nme.apply)
14451437
@tu lazy val ContextFunction0_apply: Symbol = ContextFunction0.requiredMethod(nme.apply)
@@ -1449,12 +1441,14 @@ class Definitions {
14491441
@tu lazy val Function2: Symbol = FunctionSymbol(2)
14501442
@tu lazy val ContextFunction0: Symbol = FunctionSymbol(0, isContextual = true)
14511443

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

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

1450+
lazy val ErasedFunctionClass = requiredClass("scala.runtime.ErasedFunction")
1451+
14581452
/** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */
14591453
def scalaClassName(cls: Symbol)(using Context): TypeName = cls.denot match
14601454
case clsd: ClassDenotation if clsd.owner eq ScalaPackageClass =>
@@ -1485,10 +1479,9 @@ class Definitions {
14851479

14861480
/** Is any function class where
14871481
* - FunctionXXL
1482+
* - ErasedFunction
14881483
* - FunctionN for N >= 0
14891484
* - ContextFunctionN for N >= 0
1490-
* - ErasedFunctionN for N > 0
1491-
* - ErasedContextFunctionN for N > 0
14921485
*/
14931486
def isFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isFunction
14941487

@@ -1507,12 +1500,6 @@ class Definitions {
15071500
*/
15081501
def isContextFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isContextFunction
15091502

1510-
/** Is an erased function class.
1511-
* - ErasedFunctionN for N > 0
1512-
* - ErasedContextFunctionN for N > 0
1513-
*/
1514-
def isErasedFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isErasedFunction
1515-
15161503
/** Is either FunctionXXL or a class that will be erased to FunctionXXL
15171504
* - FunctionXXL
15181505
* - FunctionN for N >= 22
@@ -1549,8 +1536,7 @@ class Definitions {
15491536
*/
15501537
def functionTypeErasure(cls: Symbol): Type =
15511538
val arity = scalaClassName(cls).functionArity
1552-
if cls.name.isErasedFunction then FunctionType(0)
1553-
else if arity > 22 then FunctionXXLClass.typeRef
1539+
if arity > 22 then FunctionXXLClass.typeRef
15541540
else if arity >= 0 then FunctionType(arity)
15551541
else NoType
15561542

@@ -1681,13 +1667,13 @@ class Definitions {
16811667
arity >= 0
16821668
&& isFunctionClass(sym)
16831669
&& tp.isRef(
1684-
FunctionType(arity, sym.name.isContextFunction, sym.name.isErasedFunction).typeSymbol,
1670+
FunctionType(arity, sym.name.isContextFunction).typeSymbol,
16851671
skipRefined = false)
16861672
end isNonRefinedFunction
16871673

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

16921678
def isFunctionOrPolyType(tp: Type)(using Context): Boolean =
16931679
isFunctionType(tp) || (tp.typeSymbol eq defn.PolyFunctionClass)
@@ -1779,7 +1765,7 @@ class Definitions {
17791765
@tu lazy val FunctionSpecializedApplyNames: collection.Set[Name] =
17801766
Function0SpecializedApplyNames ++ Function1SpecializedApplyNames ++ Function2SpecializedApplyNames
17811767

1782-
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
17831769

17841770
/** Return underlying context function type (i.e. instance of an ContextFunctionN class)
17851771
* or NoType if none exists. The following types are considered as underlying types:
@@ -1791,6 +1777,8 @@ class Definitions {
17911777
tp.stripTypeVar.dealias match
17921778
case tp1: TypeParamRef if ctx.typerState.constraint.contains(tp1) =>
17931779
asContextFunctionType(TypeComparer.bounds(tp1).hiBound)
1780+
case tp1 @ RefinedType(parent, nme.apply, mt: MethodType) if isErasedFunctionType(parent) && mt.isContextualMethod =>
1781+
tp1
17941782
case tp1 =>
17951783
if tp1.typeSymbol.name.isContextFunction && isFunctionType(tp1) then tp1
17961784
else NoType
@@ -1804,18 +1792,28 @@ class Definitions {
18041792
* types `As`, the result type `B` and a whether the type is an erased context function.
18051793
*/
18061794
object ContextFunctionType:
1807-
def unapply(tp: Type)(using Context): Option[(List[Type], Type, Boolean)] =
1795+
def unapply(tp: Type)(using Context): Option[(List[Type], Type, List[Boolean])] =
18081796
if ctx.erasedTypes then
18091797
atPhase(erasurePhase)(unapply(tp))
18101798
else
1811-
val tp1 = asContextFunctionType(tp)
1812-
if tp1.exists then
1813-
val args = tp1.dropDependentRefinement.argInfos
1814-
Some((args.init, args.last, tp1.typeSymbol.name.isErasedFunction))
1815-
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+
}
18161814

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

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

0 commit comments

Comments
 (0)