Skip to content

Commit 84e7818

Browse files
committed
Use refined traits for erased functions
- `newFunctionNType` only emits empty traits for erased functions. - function types with erased parameters are now always refined with the correct `apply` definition, for example: ErasedFunction2[Int, Int, Int] { def apply(x1: Int, erased x2: Int): Int }
1 parent 5f0cc46 commit 84e7818

File tree

4 files changed

+32
-33
lines changed

4 files changed

+32
-33
lines changed

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

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -105,19 +105,13 @@ class Definitions {
105105
* def apply(using $x0: T0, ..., $x{N_1}: T{N-1}): R
106106
* }
107107
*
108-
* ErasedFunctionN traits follow this template:
108+
* ErasedFunctionN traits follow this template (they need to be refined):
109109
*
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:
110+
* trait ErasedFunctionN[-T0,...,-T{N-1}, +R] extends Object
115111
*
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-
* }
112+
* ErasedContextFunctionN traits follow this template (they need to be refined):
119113
*
120-
* ErasedFunctionN and ErasedContextFunctionN erase to Function0.
114+
* trait ErasedContextFunctionN[-T0,...,-T{N-1}, +R] extend Object
121115
*
122116
* ImpureXYZFunctionN follow this template:
123117
*
@@ -147,11 +141,12 @@ class Definitions {
147141
enterTypeParam(cls, paramNamePrefix ++ "T" ++ (i + 1).toString, Contravariant, decls).typeRef
148142
}
149143
val resParamRef = enterTypeParam(cls, paramNamePrefix ++ "R", Covariant, decls).typeRef
150-
val methodType = MethodType.companion(
151-
isContextual = name.isContextFunction,
152-
isImplicit = false,
153-
isErased = List(name.isErasedFunction)) // TODO @natsukagami fix this
154-
decls.enter(newMethod(cls, nme.apply, methodType(argParamRefs, resParamRef), Deferred))
144+
if !name.isErasedFunction then
145+
val methodType = MethodType.companion(
146+
isContextual = name.isContextFunction,
147+
isImplicit = false,
148+
isErased = List())
149+
decls.enter(newMethod(cls, nme.apply, methodType(argParamRefs, resParamRef), Deferred))
155150
denot.info =
156151
ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: Nil, decls)
157152
}

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

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -208,15 +208,8 @@ object NameOps {
208208
if str == mustHave then found = true
209209
idx + str.length
210210
else idx
211-
def skipErased(idx: Int) =
212-
val erased = "Erased"
213-
if first.startsWith(erased, idx) then
214-
var ptr = idx + erased.length
215-
while first(ptr) != 'X' do { ptr += 1 }
216-
ptr + 1
217-
else idx
218211

219-
skip(skipErased(skip(0, "Impure")), "Context") == suffixStart
212+
skip(skip(skip(0, "Impure"), "Erased"), "Context") == suffixStart
220213
&& found
221214
}
222215

@@ -243,7 +236,7 @@ object NameOps {
243236
isFunctionPrefix(suffixStart, mustHave) && funArity(suffixStart) >= 0
244237

245238
def isContextFunction(using Context): Boolean = isSpecificFunction("Context")
246-
def isErasedFunction(using Context): Boolean = isSpecificFunction("Erased") // TODO @natsukagami change this
239+
def isErasedFunction(using Context): Boolean = isSpecificFunction("Erased")
247240
def isImpureFunction(using Context): Boolean = isSpecificFunction("Impure")
248241

249242
/** Is a synthetic function name, i.e. one of

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1835,6 +1835,7 @@ 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")
18381839
val formals1 = if (dropLast == 0) mt.paramInfos else mt.paramInfos dropRight dropLast
18391840
val isContextual = mt.isContextualMethod && !ctx.erasedTypes
18401841
val isErased = mt.isErasedMethod && !ctx.erasedTypes // TODO @natsukagami fix this
@@ -1845,7 +1846,7 @@ object Types {
18451846
val funType = defn.FunctionOf(
18461847
formals1 mapConserve (_.translateFromRepeated(toArray = isJava)),
18471848
result1, isContextual, isErased)
1848-
if alwaysDependent || mt.isResultDependent then RefinedType(funType, nme.apply, mt)
1849+
if alwaysDependent || isErased || mt.isResultDependent then RefinedType(funType, nme.apply, mt)
18491850
else funType
18501851
}
18511852

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

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
12991299

13001300
val numArgs = args.length
13011301
val isContextual = funFlags.is(Given)
1302-
val isErased = funFlags.is(Erased)
1302+
val isErased = args.collect({ case x: untpd.ValDef => x }).exists(_.mods.flags.is(Erased))
13031303
val isImpure = funFlags.is(Impure)
13041304
val funSym = defn.FunctionSymbol(numArgs, isContextual, isErased, isImpure)
13051305

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

13591359
val isContextual = tree match {
@@ -1459,9 +1459,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14591459

14601460
val (protoFormals, resultTpt) = decomposeProtoFunction(pt, params.length, tree.srcPos)
14611461

1462-
def protoFormal(i: Int): Type =
1463-
if (protoFormals.length == params.length) protoFormals(i)
1464-
else errorType(WrongNumberOfParameters(protoFormals.length), tree.srcPos)
1462+
val protoIsErased = pt match {
1463+
case RefinedType(_, _, mt: MethodType) if mt.isErasedMethod =>
1464+
mt.companion.asInstanceOf[ErasedMethodCompanion].isErased
1465+
case _ => List.fill(protoFormals.length)(false)
1466+
}
1467+
1468+
/** Returns the type and whether the parameter is erased */
1469+
def protoFormal(i: Int): (Type, Boolean) =
1470+
if (protoFormals.length == params.length) (protoFormals(i), protoIsErased(i))
1471+
else (errorType(WrongNumberOfParameters(protoFormals.length), tree.srcPos), false)
14651472

14661473
/** Is `formal` a product type which is elementwise compatible with `params`? */
14671474
def ptIsCorrectProduct(formal: Type) =
@@ -1499,7 +1506,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14991506
for ((param, i) <- params.zipWithIndex) yield
15001507
if (!param.tpt.isEmpty) param
15011508
else
1502-
val formal = protoFormal(i)
1509+
val (formal, isErased) = protoFormal(i)
15031510
val knownFormal = isFullyDefined(formal, ForceDegree.failBottom)
15041511
val paramType =
15051512
if knownFormal then formal
@@ -1510,14 +1517,17 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
15101517
.withType(paramType.translateFromRepeated(toArray = false))
15111518
.withSpan(param.span.endPos)
15121519
)
1513-
cpy.ValDef(param)(tpt = paramTpt)
1520+
val param1 = if isErased then param.withAddedFlags(Flags.Erased) else param
1521+
println(s" > $param1 => $paramType => ${param1.mods.flags.is(Flags.Erased)}")
1522+
cpy.ValDef(param1)(tpt = paramTpt)
15141523
desugared = desugar.makeClosure(inferredParams, fnBody, resultTpt, isContextual, tree.span)
1524+
println(s">> ${desugared.show}")
15151525

15161526
typed(desugared, pt)
15171527
.showing(i"desugared fun $tree --> $desugared with pt = $pt", typr)
15181528
}
15191529

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

0 commit comments

Comments
 (0)