Skip to content

Commit c57b95b

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 b8ad7b1 commit c57b95b

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

+495
-261
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
@@ -960,7 +960,9 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
960960
&& tree.isTerm
961961
&& {
962962
val qualType = tree.qualifier.tpe
963-
hasRefinement(qualType) && !qualType.derivesFrom(defn.PolyFunctionClass)
963+
hasRefinement(qualType) &&
964+
!qualType.derivesFrom(defn.PolyFunctionClass) &&
965+
!defn.isErasedFunctionType(qualType)
964966
}
965967
def loop(tree: Tree): Boolean = tree match
966968
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 _ =>
@@ -1134,10 +1134,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11341134

11351135
def etaExpandCFT(using Context): Tree =
11361136
def expand(target: Tree, tp: Type)(using Context): Tree = tp match
1137-
case defn.ContextFunctionType(argTypes, resType, isErased) =>
1137+
case defn.ContextFunctionType(argTypes, resType, erasedParams) =>
11381138
val anonFun = newAnonFun(
11391139
ctx.owner,
1140-
MethodType.companion(isContextual = true, isErased = isErased)(argTypes, resType),
1140+
MethodType.companion(isContextual = true, erasedParams = erasedParams)(argTypes, resType),
11411141
coord = ctx.owner.coord)
11421142
def lambdaBody(refss: List[List[Tree]]) =
11431143
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)
@@ -1101,15 +1086,24 @@ class Definitions {
11011086
sym.owner.linkedClass.typeRef
11021087

11031088
object FunctionOf {
1104-
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false, isErased: Boolean = false)(using Context): Type =
1105-
FunctionType(args.length, isContextual, isErased).appliedTo(args ::: resultType :: Nil)
1106-
def unapply(ft: Type)(using Context): Option[(List[Type], Type, Boolean, Boolean)] = {
1107-
val tsym = ft.typeSymbol
1108-
if isFunctionClass(tsym) && ft.isRef(tsym) then
1109-
val targs = ft.dealias.argInfos
1110-
if (targs.isEmpty) None
1111-
else Some(targs.init, targs.last, tsym.name.isContextFunction, tsym.name.isErasedFunction)
1112-
else None
1089+
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false, erasedParams: List[Boolean] = List())(using Context): Type =
1090+
assert(erasedParams.size == 0 || args.size == erasedParams.size)
1091+
if erasedParams.contains(true) then
1092+
val mt = MethodType.companion(isContextual, false, erasedParams.padTo(args.size, false))(args, resultType)
1093+
RefinedType(ErasedFunctionClass.typeRef, nme.apply, mt)
1094+
else
1095+
FunctionType(args.length, isContextual).appliedTo(args ::: resultType :: Nil)
1096+
def unapply(ft: Type)(using Context): Option[(List[Type], Type, Boolean, List[Boolean])] = {
1097+
ft.dealias match
1098+
case RefinedType(parent, nme.apply, mt: MethodType) if isErasedFunctionType(parent) =>
1099+
Some(mt.paramInfos, mt.resType, mt.isContextualMethod, mt.erasedParams)
1100+
case _ =>
1101+
val tsym = ft.dealias.typeSymbol
1102+
if isFunctionSymbol(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, List.fill(targs.init.size) { false })
1106+
else None
11131107
}
11141108
}
11151109

@@ -1428,24 +1422,22 @@ class Definitions {
14281422
classRefs(n).nn
14291423
end FunType
14301424

1431-
private def funTypeIdx(isContextual: Boolean, isErased: Boolean, isImpure: Boolean): Int =
1425+
private def funTypeIdx(isContextual: Boolean, isImpure: Boolean): Int =
14321426
(if isContextual then 1 else 0)
1433-
+ (if isErased then 2 else 0)
1434-
+ (if isImpure then 4 else 0)
1427+
+ (if isImpure then 2 else 0)
14351428

14361429
private val funTypeArray: IArray[FunType] =
14371430
val arr = Array.ofDim[FunType](8)
14381431
val choices = List(false, true)
1439-
for contxt <- choices; erasd <- choices; impure <- choices do
1432+
for contxt <- choices; impure <- choices do
14401433
var str = "Function"
14411434
if contxt then str = "Context" + str
1442-
if erasd then str = "Erased" + str
14431435
if impure then str = "Impure" + str
1444-
arr(funTypeIdx(contxt, erasd, impure)) = FunType(str)
1436+
arr(funTypeIdx(contxt, impure)) = FunType(str)
14451437
IArray.unsafeFromArray(arr)
14461438

1447-
def FunctionSymbol(n: Int, isContextual: Boolean = false, isErased: Boolean = false, isImpure: Boolean = false)(using Context): Symbol =
1448-
funTypeArray(funTypeIdx(isContextual, isErased, isImpure))(n).symbol
1439+
def FunctionSymbol(n: Int, isContextual: Boolean = false, isImpure: Boolean = false)(using Context): Symbol =
1440+
funTypeArray(funTypeIdx(isContextual, isImpure))(n).symbol
14491441

14501442
@tu lazy val Function0_apply: Symbol = Function0.requiredMethod(nme.apply)
14511443
@tu lazy val ContextFunction0_apply: Symbol = ContextFunction0.requiredMethod(nme.apply)
@@ -1455,12 +1447,14 @@ class Definitions {
14551447
@tu lazy val Function2: Symbol = FunctionSymbol(2)
14561448
@tu lazy val ContextFunction0: Symbol = FunctionSymbol(0, isContextual = true)
14571449

1458-
def FunctionType(n: Int, isContextual: Boolean = false, isErased: Boolean = false, isImpure: Boolean = false)(using Context): TypeRef =
1459-
FunctionSymbol(n, isContextual && !ctx.erasedTypes, isErased, isImpure).typeRef
1450+
def FunctionType(n: Int, isContextual: Boolean = false, isImpure: Boolean = false)(using Context): TypeRef =
1451+
FunctionSymbol(n, isContextual && !ctx.erasedTypes, isImpure).typeRef
14601452

14611453
lazy val PolyFunctionClass = requiredClass("scala.PolyFunction")
14621454
def PolyFunctionType = PolyFunctionClass.typeRef
14631455

1456+
lazy val ErasedFunctionClass = requiredClass("scala.runtime.ErasedFunction")
1457+
14641458
/** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */
14651459
def scalaClassName(cls: Symbol)(using Context): TypeName = cls.denot match
14661460
case clsd: ClassDenotation if clsd.owner eq ScalaPackageClass =>
@@ -1491,10 +1485,9 @@ class Definitions {
14911485

14921486
/** Is any function class where
14931487
* - FunctionXXL
1488+
* - ErasedFunction
14941489
* - FunctionN for N >= 0
14951490
* - ContextFunctionN for N >= 0
1496-
* - ErasedFunctionN for N > 0
1497-
* - ErasedContextFunctionN for N > 0
14981491
*/
14991492
def isFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isFunction
15001493

@@ -1513,12 +1506,6 @@ class Definitions {
15131506
*/
15141507
def isContextFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isContextFunction
15151508

1516-
/** Is an erased function class.
1517-
* - ErasedFunctionN for N > 0
1518-
* - ErasedContextFunctionN for N > 0
1519-
*/
1520-
def isErasedFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isErasedFunction
1521-
15221509
/** Is either FunctionXXL or a class that will be erased to FunctionXXL
15231510
* - FunctionXXL
15241511
* - FunctionN for N >= 22
@@ -1555,8 +1542,7 @@ class Definitions {
15551542
*/
15561543
def functionTypeErasure(cls: Symbol): Type =
15571544
val arity = scalaClassName(cls).functionArity
1558-
if cls.name.isErasedFunction then FunctionType(0)
1559-
else if arity > 22 then FunctionXXLClass.typeRef
1545+
if arity > 22 then FunctionXXLClass.typeRef
15601546
else if arity >= 0 then FunctionType(arity)
15611547
else NoType
15621548

@@ -1696,13 +1682,13 @@ class Definitions {
16961682
arity >= 0
16971683
&& isFunctionClass(sym)
16981684
&& tp.isRef(
1699-
FunctionType(arity, sym.name.isContextFunction, sym.name.isErasedFunction).typeSymbol,
1685+
FunctionType(arity, sym.name.isContextFunction).typeSymbol,
17001686
skipRefined = false)
17011687
end isNonRefinedFunction
17021688

17031689
/** Is `tp` a representation of a (possibly dependent) function type or an alias of such? */
17041690
def isFunctionType(tp: Type)(using Context): Boolean =
1705-
isNonRefinedFunction(tp.dropDependentRefinement)
1691+
isNonRefinedFunction(tp.dropDependentRefinement) || isErasedFunctionType(tp)
17061692

17071693
def isFunctionOrPolyType(tp: Type)(using Context): Boolean =
17081694
isFunctionType(tp) || (tp.typeSymbol eq defn.PolyFunctionClass)
@@ -1794,7 +1780,7 @@ class Definitions {
17941780
@tu lazy val FunctionSpecializedApplyNames: collection.Set[Name] =
17951781
Function0SpecializedApplyNames ++ Function1SpecializedApplyNames ++ Function2SpecializedApplyNames
17961782

1797-
def functionArity(tp: Type)(using Context): Int = tp.dropDependentRefinement.dealias.argInfos.length - 1
1783+
def functionArity(tp: Type)(using Context): Int = tp.functionArgInfos.length - 1
17981784

17991785
/** Return underlying context function type (i.e. instance of an ContextFunctionN class)
18001786
* or NoType if none exists. The following types are considered as underlying types:
@@ -1806,6 +1792,8 @@ class Definitions {
18061792
tp.stripTypeVar.dealias match
18071793
case tp1: TypeParamRef if ctx.typerState.constraint.contains(tp1) =>
18081794
asContextFunctionType(TypeComparer.bounds(tp1).hiBound)
1795+
case tp1 @ RefinedType(parent, nme.apply, mt: MethodType) if isErasedFunctionType(parent) && mt.isContextualMethod =>
1796+
tp1
18091797
case tp1 =>
18101798
if tp1.typeSymbol.name.isContextFunction && isFunctionType(tp1) then tp1
18111799
else NoType
@@ -1819,18 +1807,28 @@ class Definitions {
18191807
* types `As`, the result type `B` and a whether the type is an erased context function.
18201808
*/
18211809
object ContextFunctionType:
1822-
def unapply(tp: Type)(using Context): Option[(List[Type], Type, Boolean)] =
1810+
def unapply(tp: Type)(using Context): Option[(List[Type], Type, List[Boolean])] =
18231811
if ctx.erasedTypes then
18241812
atPhase(erasurePhase)(unapply(tp))
18251813
else
1826-
val tp1 = asContextFunctionType(tp)
1827-
if tp1.exists then
1828-
val args = tp1.dropDependentRefinement.argInfos
1829-
Some((args.init, args.last, tp1.typeSymbol.name.isErasedFunction))
1830-
else None
1814+
asContextFunctionType(tp) match
1815+
case RefinedType(parent, nme.apply, mt: MethodType) if isErasedFunctionType(parent) =>
1816+
Some((mt.paramInfos, mt.resType, mt.erasedParams))
1817+
case tp1 if tp1.exists =>
1818+
val args = tp1.functionArgInfos
1819+
val erasedParams = erasedFunctionParameters(tp1)
1820+
Some((args.init, args.last, erasedParams))
1821+
case _ => None
1822+
1823+
/* Returns a list of erased booleans marking whether parameters are erased, for a function type. */
1824+
def erasedFunctionParameters(tp: Type)(using Context): List[Boolean] = tp.dealias match {
1825+
case RefinedType(parent, nme.apply, mt: MethodType) => mt.erasedParams
1826+
case tp if isFunctionType(tp) => List.fill(functionArity(tp)) { false }
1827+
case _ => Nil
1828+
}
18311829

18321830
def isErasedFunctionType(tp: Type)(using Context): Boolean =
1833-
tp.dealias.typeSymbol.name.isErasedFunction && isFunctionType(tp)
1831+
tp.derivesFrom(defn.ErasedFunctionClass)
18341832

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

0 commit comments

Comments
 (0)