Skip to content

Commit 6c4d7bf

Browse files
committed
Create classes for erased method companions
Extends the original idea of having `Erased...MethodCompanion` as objects, we now have `Erased...MethodCompanion` classes, with each instance holding a bool array of erased/non-erased marker for its parameters. Some functions now take a `List[Boolean]` for `isErased` parameter, but this is largely WIP and only for making the compiler compiles. :P Those with obviously temporary patches are marked `// TODO @natsukagami`, mostly related to erased function types.
1 parent 72f0fa5 commit 6c4d7bf

File tree

11 files changed

+57
-41
lines changed

11 files changed

+57
-41
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ extension (tp: Type)
146146
defn.FunctionType(
147147
fname.functionArity,
148148
isContextual = fname.isContextFunction,
149-
isErased = fname.isErasedFunction,
149+
isErased = fname.isErasedFunction, // TODO @natsukagami fix this
150150
isImpure = true).appliedTo(args)
151151
case _ =>
152152
tp

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,8 @@ class CheckCaptures extends Recheck, SymTransformer:
612612
super.checkConformsExpr(actual1, expected1, tree)
613613

614614
private def toDepFun(args: List[Type], resultType: Type, isContextual: Boolean, isErased: Boolean)(using Context): Type =
615-
MethodType.companion(isContextual = isContextual, isErased = isErased)(args, resultType)
615+
val erasedParams = args.map(_ => isErased) // TODO @natsukagami fix
616+
MethodType.companion(isContextual = isContextual, isErased = erasedParams)(args, resultType)
616617
.toFunctionType(isJava = false, alwaysDependent = true)
617618

618619
/** Turn `expected` into a dependent function when `actual` is dependent. */

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class Definitions {
150150
val methodType = MethodType.companion(
151151
isContextual = name.isContextFunction,
152152
isImplicit = false,
153-
isErased = name.isErasedFunction)
153+
isErased = List(name.isErasedFunction)) // TODO @natsukagami fix this
154154
decls.enter(newMethod(cls, nme.apply, methodType(argParamRefs, resParamRef), Deferred))
155155
denot.info =
156156
ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: Nil, decls)
@@ -1506,7 +1506,7 @@ class Definitions {
15061506
* - ErasedFunctionN for N > 0
15071507
* - ErasedContextFunctionN for N > 0
15081508
*/
1509-
def isErasedFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isErasedFunction
1509+
def isErasedFunctionClass(cls: Symbol): List[Boolean] = List(scalaClassName(cls).isErasedFunction) // TODO @natsukagami fix this
15101510

15111511
/** Is either FunctionXXL or a class that will be erased to FunctionXXL
15121512
* - FunctionXXL
@@ -1799,18 +1799,19 @@ class Definitions {
17991799
* types `As`, the result type `B` and a whether the type is an erased context function.
18001800
*/
18011801
object ContextFunctionType:
1802-
def unapply(tp: Type)(using Context): Option[(List[Type], Type, Boolean)] =
1802+
def unapply(tp: Type)(using Context): Option[(List[Type], Type, List[Boolean])] =
18031803
if ctx.erasedTypes then
18041804
atPhase(erasurePhase)(unapply(tp))
18051805
else
18061806
val tp1 = asContextFunctionType(tp)
18071807
if tp1.exists then
18081808
val args = tp1.dropDependentRefinement.argInfos
1809-
Some((args.init, args.last, tp1.typeSymbol.name.isErasedFunction))
1809+
Some((args.init, args.last, List(tp1.typeSymbol.name.isErasedFunction))) // TODO @natsukagami fix this
18101810
else None
18111811

18121812
def isErasedFunctionType(tp: Type)(using Context): Boolean =
1813-
tp.dealias.typeSymbol.name.isErasedFunction && isFunctionType(tp)
1813+
false // TODO @natsukagami fix this
1814+
// tp.dealias.typeSymbol.name.isErasedFunction && isFunctionType(tp)
18141815

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

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,15 @@ object NameOps {
208208
if str == mustHave then found = true
209209
idx + str.length
210210
else idx
211-
skip(skip(skip(0, "Impure"), "Erased"), "Context") == suffixStart
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
218+
219+
skip(skipErased(skip(0, "Impure")), "Context") == suffixStart
212220
&& found
213221
}
214222

@@ -235,7 +243,7 @@ object NameOps {
235243
isFunctionPrefix(suffixStart, mustHave) && funArity(suffixStart) >= 0
236244

237245
def isContextFunction(using Context): Boolean = isSpecificFunction("Context")
238-
def isErasedFunction(using Context): Boolean = isSpecificFunction("Erased")
246+
def isErasedFunction(using Context): Boolean = isSpecificFunction("Erased") // TODO @natsukagami change this
239247
def isImpureFunction(using Context): Boolean = isSpecificFunction("Impure")
240248

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

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ object NamerOps:
4343
resultType
4444
case TermSymbols(params) :: paramss1 =>
4545
val (isContextual, isImplicit, isErased) =
46-
if params.isEmpty then (false, false, false)
47-
else (params.head.is(Given), params.head.is(Implicit), params.head.is(Erased))
46+
if params.isEmpty then (false, false, List())
47+
else (params.head.is(Given), params.head.is(Implicit), params.map(_.is(Erased)))
4848
val make = MethodType.companion(isContextual = isContextual, isImplicit = isImplicit, isErased = isErased)
4949
if isJava then
5050
for param <- params do

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

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3899,15 +3899,15 @@ object Types {
38993899

39003900
final override def isImplicitMethod: Boolean =
39013901
companion.eq(ImplicitMethodType) ||
3902-
companion.eq(ErasedImplicitMethodType) ||
3902+
companion.isInstanceOf[ErasedImplicitMethodType] ||
39033903
isContextualMethod
39043904
final override def isErasedMethod: Boolean =
3905-
companion.eq(ErasedMethodType) ||
3906-
companion.eq(ErasedImplicitMethodType) ||
3907-
companion.eq(ErasedContextualMethodType)
3905+
companion.isInstanceOf[ErasedMethodType] ||
3906+
companion.isInstanceOf[ErasedImplicitMethodType] ||
3907+
companion.isInstanceOf[ErasedContextualMethodType]
39083908
final override def isContextualMethod: Boolean =
39093909
companion.eq(ContextualMethodType) ||
3910-
companion.eq(ErasedContextualMethodType)
3910+
companion.isInstanceOf[ErasedContextualMethodType]
39113911

39123912
protected def prefixString: String = companion.prefixString
39133913
}
@@ -4019,19 +4019,22 @@ object Types {
40194019
}
40204020

40214021
object MethodType extends MethodTypeCompanion("MethodType") {
4022-
def companion(isContextual: Boolean = false, isImplicit: Boolean = false, isErased: Boolean = false): MethodTypeCompanion =
4022+
def companion(isContextual: Boolean = false, isImplicit: Boolean = false, isErased: List[Boolean] = List()): MethodTypeCompanion =
4023+
val hasErased = isErased.exists(_ == true)
40234024
if (isContextual)
4024-
if (isErased) ErasedContextualMethodType else ContextualMethodType
4025+
if (hasErased) ErasedContextualMethodType(isErased) else ContextualMethodType
40254026
else if (isImplicit)
4026-
if (isErased) ErasedImplicitMethodType else ImplicitMethodType
4027+
if (hasErased) ErasedImplicitMethodType(isErased) else ImplicitMethodType
40274028
else
4028-
if (isErased) ErasedMethodType else MethodType
4029+
if (hasErased) ErasedMethodType(isErased) else MethodType
40294030
}
4030-
object ErasedMethodType extends MethodTypeCompanion("ErasedMethodType")
4031+
private def erasedMt(t: String, isErased: List[Boolean]) =
4032+
s"Erased${t}(${isErased.map(if _ then "erased _" else "_").mkString(", ")})"
4033+
class ErasedMethodType(val isErased: List[Boolean]) extends MethodTypeCompanion(erasedMt("MethodType", isErased))
40314034
object ContextualMethodType extends MethodTypeCompanion("ContextualMethodType")
4032-
object ErasedContextualMethodType extends MethodTypeCompanion("ErasedContextualMethodType")
4035+
class ErasedContextualMethodType(val isErased: List[Boolean]) extends MethodTypeCompanion(erasedMt("ContextualMethodType", isErased))
40334036
object ImplicitMethodType extends MethodTypeCompanion("ImplicitMethodType")
4034-
object ErasedImplicitMethodType extends MethodTypeCompanion("ErasedImplicitMethodType")
4037+
class ErasedImplicitMethodType(val isErased: List[Boolean]) extends MethodTypeCompanion(erasedMt("ImplicitMethodType", isErased))
40354038

40364039
/** A ternary extractor for MethodType */
40374040
object MethodTpe {

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,9 +402,9 @@ class TreeUnpickler(reader: TastyReader,
402402
case METHODtype =>
403403
def methodTypeCompanion(mods: FlagSet): MethodTypeCompanion =
404404
if mods.is(Implicit) then ImplicitMethodType
405-
else if mods.isAllOf(Erased | Given) then ErasedContextualMethodType
405+
// else if mods.isAllOf(Erased | Given) then ErasedContextualMethodType // TODO @natsukagami handle this
406406
else if mods.is(Given) then ContextualMethodType
407-
else if mods.is(Erased) then ErasedMethodType
407+
// else if mods.is(Erased) then ErasedMethodType // TODO @natsukagami handle this
408408
else MethodType
409409
readMethodic(methodTypeCompanion, _.toTermName)
410410
case TYPELAMBDAtype =>

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,17 @@ class PlainPrinter(_ctx: Context) extends Printer {
120120
}
121121
(keyword ~ refinementNameString(rt) ~ toTextRHS(rt.refinedInfo)).close
122122

123-
protected def argText(arg: Type): Text = homogenizeArg(arg) match {
123+
protected def argText(arg: Type, isErased: Boolean = false): Text = keywordText("erased ").provided(isErased) ~ (homogenizeArg(arg) match {
124124
case arg: TypeBounds => "?" ~ toText(arg)
125125
case arg => toText(arg)
126-
}
126+
})
127127

128128
/** Pretty-print comma-separated type arguments for a constructor to be inserted among parentheses or brackets
129129
* (hence with `GlobalPrec` precedence).
130130
*/
131-
protected def argsText(args: List[Type]): Text =
132-
atPrec(GlobalPrec) { Text(args.map(arg => argText(arg) ), ", ") }
131+
protected def argsText(args: List[Type], _erased: List[Boolean] = List()): Text =
132+
val erased = _erased.padTo(args.length, false)
133+
atPrec(GlobalPrec) { Text(args.zip(erased).map((arg, erased) => argText(arg, erased)), ", ") }
133134

134135
/** The longest sequence of refinement types, starting at given type
135136
* and following parents.

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,20 +147,19 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
147147
def toTextTuple(args: List[Type]): Text =
148148
"(" ~ argsText(args) ~ ")"
149149

150-
def toTextFunction(args: List[Type], isGiven: Boolean, isErased: Boolean, isPure: Boolean): Text =
150+
def toTextFunction(args: List[Type], isGiven: Boolean, isErased: List[Boolean], isPure: Boolean): Text =
151151
changePrec(GlobalPrec) {
152152
val argStr: Text =
153153
if args.length == 2
154154
&& !defn.isTupleNType(args.head)
155-
&& !isGiven && !isErased
155+
&& !isGiven
156156
then
157-
atPrec(InfixPrec) { argText(args.head) }
157+
atPrec(InfixPrec) { argText(args.head, isErased.headOption.getOrElse(false)) }
158158
else
159159
"("
160-
~ keywordText("erased ").provided(isErased)
161-
~ argsText(args.init)
160+
~ argsText(args.init, isErased)
162161
~ ")"
163-
argStr ~ " " ~ arrow(isGiven, isPure) ~ " " ~ argText(args.last)
162+
argStr ~ " " ~ arrow(isGiven, isPure) ~ " " ~ argText(args.last, false)
164163
}
165164

166165
def toTextMethodAsFunction(info: Type, isPure: Boolean): Text = info match
@@ -225,7 +224,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
225224
if tycon.isRepeatedParam then toTextLocal(args.head) ~ "*"
226225
else if tp.isConvertibleParam then "into " ~ toText(args.head)
227226
else if defn.isFunctionSymbol(tsym) then
228-
toTextFunction(args, tsym.name.isContextFunction, tsym.name.isErasedFunction,
227+
toTextFunction(args, tsym.name.isContextFunction, List(tsym.name.isErasedFunction) /* TODO @natsukagami fix this */,
229228
isPure = Feature.pureFunsEnabled && !tsym.name.isImpureFunction)
230229
else if isInfixType(tp) then
231230
val l :: r :: Nil = args: @unchecked

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,10 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(using Context) {
131131
else
132132
val defn.ContextFunctionType(argTypes, resType, isErased) = tp: @unchecked
133133
val anonFun = newAnonFun(ctx.owner,
134-
MethodType(if isErased then Nil else argTypes, resType),
134+
MethodType(
135+
argTypes.zip(isErased.padTo(argTypes.length, false))
136+
.flatMap((t, e) => if e then List(t) else List()),
137+
resType),
135138
coord = ctx.owner.coord)
136139
anonFun.info = transformInfo(anonFun, anonFun.info)
137140

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ object ContextFunctionResults:
5858
*/
5959
def contextResultsAreErased(sym: Symbol)(using Context): Boolean =
6060
def allErased(tp: Type): Boolean = tp.dealias match
61-
case defn.ContextFunctionType(_, resTpe, isErased) => isErased && allErased(resTpe)
61+
case defn.ContextFunctionType(_, resTpe, isErased) => isErased.forall(_ == true) && allErased(resTpe)
6262
case _ => true
6363
contextResultCount(sym) > 0 && allErased(sym.info.finalResultType)
6464

@@ -74,7 +74,7 @@ object ContextFunctionResults:
7474
tp.derivedLambdaType(resType = integrateContextResults(tp.resType, crCount))
7575
case defn.ContextFunctionType(argTypes, resType, isErased) =>
7676
val methodType: MethodTypeCompanion =
77-
if isErased then ErasedMethodType else MethodType
77+
if isErased.exists(_ == true) then ErasedMethodType(isErased) else MethodType
7878
methodType(argTypes, integrateContextResults(resType, crCount - 1))
7979

8080
/** The total number of parameters of method `sym`, not counting
@@ -87,7 +87,7 @@ object ContextFunctionResults:
8787
else
8888
val defn.ContextFunctionType(params, resTpe, isErased) = tp: @unchecked
8989
val rest = contextParamCount(resTpe, crCount - 1)
90-
if isErased then rest else params.length + rest
90+
if isErased.exists(_ == true) then isErased.count(_ == false) + rest else params.length + rest
9191

9292
def normalParamCount(tp: Type): Int = tp.widenExpr.stripPoly match
9393
case mt @ MethodType(pnames) =>
@@ -133,4 +133,4 @@ object ContextFunctionResults:
133133
case _ =>
134134
false
135135

136-
end ContextFunctionResults
136+
end ContextFunctionResults

0 commit comments

Comments
 (0)