Skip to content

Commit 3ca8073

Browse files
committed
Handle ErasedFunctions as refined traits
1 parent 84e7818 commit 3ca8073

File tree

8 files changed

+41
-16
lines changed

8 files changed

+41
-16
lines changed

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.isErasedFunctionClass(qualType.typeSymbol)
912914
}
913915
def loop(tree: Tree): Boolean = tree match
914916
case TypeApply(fun, _) =>

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ extends tpd.TreeTraverser:
3535
* arguments `argTypes` and result `resType`.
3636
*/
3737
private def depFun(tycon: Type, argTypes: List[Type], resType: Type)(using Context): Type =
38+
assert(!defn.isErasedFunctionClass(tycon.classSymbol)) // TODO @natsukagami not sure how to know
39+
// erased parameter info here.
3840
MethodType.companion(
3941
isContextual = defn.isContextFunctionClass(tycon.classSymbol),
40-
isErased = defn.isErasedFunctionClass(tycon.classSymbol)
42+
isErased = List()
4143
)(argTypes, resType)
4244
.toFunctionType(isJava = false, alwaysDependent = true)
4345

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,7 @@ class Definitions {
15011501
* - ErasedFunctionN for N > 0
15021502
* - ErasedContextFunctionN for N > 0
15031503
*/
1504-
def isErasedFunctionClass(cls: Symbol): List[Boolean] = List(scalaClassName(cls).isErasedFunction) // TODO @natsukagami fix this
1504+
def isErasedFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isErasedFunction // TODO @natsukagami fix this
15051505

15061506
/** Is either FunctionXXL or a class that will be erased to FunctionXXL
15071507
* - FunctionXXL
@@ -1539,8 +1539,7 @@ class Definitions {
15391539
*/
15401540
def functionTypeErasure(cls: Symbol): Type =
15411541
val arity = scalaClassName(cls).functionArity
1542-
if cls.name.isErasedFunction then FunctionType(0)
1543-
else if arity > 22 then FunctionXXLClass.typeRef
1542+
if arity > 22 then FunctionXXLClass.typeRef
15441543
else if arity >= 0 then FunctionType(arity)
15451544
else NoType
15461545

@@ -1805,8 +1804,8 @@ class Definitions {
18051804
else None
18061805

18071806
def isErasedFunctionType(tp: Type)(using Context): Boolean =
1808-
false // TODO @natsukagami fix this
1809-
// tp.dealias.typeSymbol.name.isErasedFunction && isFunctionType(tp)
1807+
// false // TODO @natsukagami fix this
1808+
tp.dealias.typeSymbol.name.isErasedFunction && isFunctionType(tp)
18101809

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

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,16 @@ object TypeErasure {
536536
assert(paramss.length == 1)
537537
erasure(defn.FunctionType(paramss.head.length,
538538
isContextual = res.isImplicitMethod, isErased = res.isErasedMethod))
539+
540+
def eraseErasedFunctionApply(applyInfo: Type)(using Context): Type =
541+
val erasedFn = applyInfo.asInstanceOf[MethodType]
542+
val companion = erasedFn.companion.asInstanceOf[ErasedMethodCompanion]
543+
val fnType = defn.FunctionType(
544+
n = companion.isErased.count(_ == false),
545+
isErased = false,
546+
isContextual = erasedFn.isContextualMethod,
547+
)
548+
erasure(fnType)
539549
}
540550

541551
import TypeErasure._
@@ -612,6 +622,8 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
612622
defn.FunctionType(0)
613623
case RefinedType(parent, nme.apply, refinedInfo) if parent.typeSymbol eq defn.PolyFunctionClass =>
614624
erasePolyFunctionApply(refinedInfo)
625+
case RefinedType(parent, nme.apply, refinedInfo) if defn.isErasedFunctionClass(parent.typeSymbol) =>
626+
eraseErasedFunctionApply(refinedInfo)
615627
case tp: TypeProxy =>
616628
this(tp.underlying)
617629
case tp @ AndType(tp1, tp2) =>
@@ -648,14 +660,14 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
648660
val formals = formals0.mapConserve(paramErasure)
649661
eraseResult(tp.resultType) match {
650662
case rt: MethodType =>
651-
tp.derivedLambdaType(names ++ rt.paramNames, formals ++ rt.paramInfos, rt.resultType)
663+
tp.withoutErased.derivedLambdaType(names ++ rt.paramNames, formals ++ rt.paramInfos, rt.resultType)
652664
case NoType =>
653665
// Can happen if we smuggle in a Nothing in the qualifier. Normally we prevent that
654666
// in Checking.checkMembersOK, but compiler-generated code can bypass this test.
655667
// See i15377.scala for a test case.
656668
NoType
657669
case rt =>
658-
tp.derivedLambdaType(names, formals, rt)
670+
tp.withoutErased.derivedLambdaType(names, formals, rt)
659671
}
660672
case tp: PolyType =>
661673
this(tp.resultType)
@@ -864,6 +876,8 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
864876
// because RefinedTypes <: TypeProxy and it would be caught by
865877
// the case immediately below
866878
sigName(this(tp))
879+
case tp @ RefinedType(parent, nme.apply, refinedInfo) if defn.isErasedFunctionClass(parent.typeSymbol) =>
880+
sigName(this(tp))
867881
case tp: TypeProxy =>
868882
sigName(tp.underlying)
869883
case tp: WildcardType =>

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1835,7 +1835,6 @@ object Types {
18351835
*/
18361836
def toFunctionType(isJava: Boolean, dropLast: Int = 0, alwaysDependent: Boolean = false)(using Context): Type = this match {
18371837
case mt: MethodType if !mt.isParamDependent =>
1838-
println(s"$mt to function type")
18391838
val formals1 = if (dropLast == 0) mt.paramInfos else mt.paramInfos dropRight dropLast
18401839
val isContextual = mt.isContextualMethod && !ctx.erasedTypes
18411840
val isErased = mt.isErasedMethod && !ctx.erasedTypes // TODO @natsukagami fix this
@@ -3912,6 +3911,15 @@ object Types {
39123911
companion.eq(ContextualMethodType) ||
39133912
companion.isInstanceOf[ErasedContextualMethodType]
39143913

3914+
def withoutErased(using Context): MethodType =
3915+
val newCompanion = companion match {
3916+
case _: ErasedMethodType => MethodType
3917+
case _: ErasedContextualMethodType => ContextualMethodType
3918+
case _: ErasedImplicitMethodType => ImplicitMethodType
3919+
case c => c
3920+
}
3921+
newCompanion(paramNames)(paramInfosExp, resultTypeExp)
3922+
39153923
protected def prefixString: String = companion.prefixString
39163924
}
39173925

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ object Erasure {
500500
if isFunction && !ctx.settings.scalajs.value then
501501
val arity = implParamTypes.length
502502
val specializedFunctionalInterface =
503-
if defn.isSpecializableFunctionSAM(implParamTypes, implResultType) then
503+
if !implType.isErasedMethod && defn.isSpecializableFunctionSAM(implParamTypes, implResultType) then
504504
// Using these subclasses is critical to avoid boxing since their
505505
// SAM is a specialized method `apply$mc*$sp` whose default
506506
// implementation in FunctionN boxes.
@@ -679,6 +679,8 @@ object Erasure {
679679
val qualTp = tree.qualifier.typeOpt.widen
680680
if qualTp.derivesFrom(defn.PolyFunctionClass) then
681681
erasePolyFunctionApply(qualTp.select(nme.apply).widen).classSymbol
682+
else if defn.isErasedFunctionType(qualTp) then
683+
eraseErasedFunctionApply(qualTp.select(nme.apply).widen).classSymbol
682684
else
683685
NoSymbol
684686
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class SpecializeFunctions extends MiniPhase {
7070
/** Dispatch to specialized `apply`s in user code when available */
7171
override def transformApply(tree: Apply)(using Context) =
7272
tree match {
73-
case Apply(fun: NameTree, args) if fun.name == nme.apply && args.size <= 3 && fun.symbol.owner.isType =>
73+
case Apply(fun: NameTree, args) if fun.name == nme.apply && args.size <= 3 && fun.symbol.exists && fun.symbol.owner.isType =>
7474
val argTypes = fun.tpe.widen.firstParamTypes.map(_.widenSingleton.dealias)
7575
val retType = tree.tpe.widenSingleton.dealias
7676
val isSpecializable =

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,7 +1353,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
13531353
}
13541354
}
13551355

1356-
def typedFunctionValue(tree: untpd.Function, pt: Type)(using Context): Tree = trace.force(s"typedFunctionValue ${tree.show} => ${pt.show}", show = true) {
1356+
def typedFunctionValue(tree: untpd.Function, pt: Type)(using Context): Tree = {
13571357
val untpd.Function(params: List[untpd.ValDef] @unchecked, _) = tree: @unchecked
13581358

13591359
val isContextual = tree match {
@@ -1518,16 +1518,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
15181518
.withSpan(param.span.endPos)
15191519
)
15201520
val param1 = if isErased then param.withAddedFlags(Flags.Erased) else param
1521-
println(s" > $param1 => $paramType => ${param1.mods.flags.is(Flags.Erased)}")
15221521
cpy.ValDef(param1)(tpt = paramTpt)
15231522
desugared = desugar.makeClosure(inferredParams, fnBody, resultTpt, isContextual, tree.span)
1524-
println(s">> ${desugared.show}")
15251523

15261524
typed(desugared, pt)
15271525
.showing(i"desugared fun $tree --> $desugared with pt = $pt", typr)
15281526
}
15291527

1530-
def typedClosure(tree: untpd.Closure, pt: Type)(using Context): Tree = trace.force(s"typedClosure ${tree.show} => ${pt.show}", show = true) {
1528+
def typedClosure(tree: untpd.Closure, pt: Type)(using Context): Tree = {
15311529
val env1 = tree.env mapconserve (typed(_))
15321530
val meth1 = typedUnadapted(tree.meth)
15331531
val target =

0 commit comments

Comments
 (0)