Skip to content

Commit 42d4d09

Browse files
committed
Use the @ErasedParam annotation as a marker for erased parameter
... instead of storing a separate boolean list. This has already been done, and will require no change to the TASTY format.
1 parent 91dc649 commit 42d4d09

18 files changed

+74
-146
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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, erasedParams) =>
1137+
case defn.ContextFunctionType(argTypes, resType, _) =>
11381138
val anonFun = newAnonFun(
11391139
ctx.owner,
1140-
MethodType.companion(isContextual = true, erasedParams = erasedParams)(argTypes, resType),
1140+
MethodType.companion(isContextual = true)(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/cc/CheckCaptures.scala

Lines changed: 8 additions & 8 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, erasedParams) =>
340-
defn.FunctionOf(paramtpe.forceBoxStatus(true) :: Nil, restpe, isContectual, erasedParams)
339+
case defn.FunctionOf(paramtpe :: Nil, restpe, isContectual) =>
340+
defn.FunctionOf(paramtpe.forceBoxStatus(true) :: Nil, restpe, isContectual)
341341
}
342342
else
343343
super.recheckApply(tree, pt) match
@@ -430,7 +430,7 @@ class CheckCaptures extends Recheck, SymTransformer:
430430
block match
431431
case closureDef(mdef) =>
432432
pt.dealias match
433-
case defn.FunctionOf(ptformals, _, _, _)
433+
case defn.FunctionOf(ptformals, _, _)
434434
if ptformals.nonEmpty && ptformals.forall(_.captureSet.isAlwaysEmpty) =>
435435
// Redo setup of the anonymous function so that formal parameters don't
436436
// get capture sets. This is important to avoid false widenings to `*`
@@ -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, erasedParams: List[Boolean])(using Context): Type =
602-
MethodType.companion(isContextual = isContextual, erasedParams = erasedParams)(args, resultType)
601+
private def toDepFun(args: List[Type], resultType: Type, isContextual: Boolean)(using Context): Type =
602+
MethodType.companion(isContextual = isContextual)(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, erasedParams)
610+
case expected @ defn.FunctionOf(args, resultType, isContextual)
611611
if defn.isNonRefinedFunction(expected) && defn.isFunctionType(actual) && !defn.isNonRefinedFunction(actual) =>
612-
val expected1 = toDepFun(args, resultType, isContextual, erasedParams)
612+
val expected1 = toDepFun(args, resultType, isContextual)
613613
expected1
614614
case _ =>
615615
expected
@@ -675,7 +675,7 @@ class CheckCaptures extends Recheck, SymTransformer:
675675

676676
try
677677
val (eargs, eres) = expected.dealias.stripCapturing match
678-
case defn.FunctionOf(eargs, eres, _, _) => (eargs, eres)
678+
case defn.FunctionOf(eargs, eres, _) => (eargs, eres)
679679
case expected: MethodType => (expected.paramInfos, expected.resType)
680680
case expected @ RefinedType(_, _, rinfo: MethodType) if defn.isFunctionType(expected) => (rinfo.paramInfos, rinfo.resType)
681681
case _ => (aargs.map(_ => WildcardType), WildcardType)

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ 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-
erasedParams = defn.erasedFunctionParameters(tycon)
4241
)(argTypes, resType)
4342
.toFunctionType(isJava = false, alwaysDependent = true)
4443

@@ -260,7 +259,7 @@ extends tpd.TreeTraverser:
260259
private def expandThrowsAlias(tp: Type)(using Context) = tp match
261260
case AppliedType(tycon, res :: exc :: Nil) if tycon.typeSymbol == defn.throwsAlias =>
262261
// 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, erasedParams = List(true))
262+
defn.FunctionOf(defn.CanThrowClass.typeRef.appliedTo(exc) :: Nil, res, isContextual = true)
264263
case _ => tp
265264

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

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

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,7 @@ class Definitions {
134134
val resParamRef = enterTypeParam(cls, paramNamePrefix ++ "R", Covariant, decls).typeRef
135135
val methodType = MethodType.companion(
136136
isContextual = name.isContextFunction,
137-
isImplicit = false,
138-
erasedParams = List())
137+
isImplicit = false)
139138
decls.enter(newMethod(cls, nme.apply, methodType(argParamRefs, resParamRef), Deferred))
140139
denot.info =
141140
ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: Nil, decls)
@@ -1086,23 +1085,22 @@ class Definitions {
10861085
sym.owner.linkedClass.typeRef
10871086

10881087
object FunctionOf {
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)
1088+
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false)(using Context): Type =
1089+
val mt = MethodType.companion(isContextual, false)(args, resultType)
1090+
if mt.hasErasedParams then
10931091
RefinedType(ErasedFunctionClass.typeRef, nme.apply, mt)
10941092
else
10951093
FunctionType(args.length, isContextual).appliedTo(args ::: resultType :: Nil)
1096-
def unapply(ft: Type)(using Context): Option[(List[Type], Type, Boolean, List[Boolean])] = {
1094+
def unapply(ft: Type)(using Context): Option[(List[Type], Type, Boolean)] = {
10971095
ft.dealias match
10981096
case RefinedType(parent, nme.apply, mt: MethodType) if isErasedFunctionType(parent) =>
1099-
Some(mt.paramInfos, mt.resType, mt.isContextualMethod, mt.erasedParams)
1097+
Some(mt.paramInfos, mt.resType, mt.isContextualMethod)
11001098
case _ =>
11011099
val tsym = ft.dealias.typeSymbol
11021100
if isFunctionSymbol(tsym) && ft.isRef(tsym) then
11031101
val targs = ft.dealias.argInfos
11041102
if (targs.isEmpty) None
1105-
else Some(targs.init, targs.last, tsym.name.isContextFunction, List.fill(targs.init.size) { false })
1103+
else Some(targs.init, targs.last, tsym.name.isContextFunction)
11061104
else None
11071105
}
11081106
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ object NamerOps:
4242
case Nil =>
4343
resultType
4444
case TermSymbols(params) :: paramss1 =>
45-
val (isContextual, isImplicit, erasedParams) =
46-
if params.isEmpty then (false, false, List())
47-
else (params.head.is(Given), params.head.is(Implicit), params.map(_.is(Erased)))
48-
val make = MethodType.companion(isContextual = isContextual, isImplicit = isImplicit, erasedParams = erasedParams)
45+
val (isContextual, isImplicit) =
46+
if params.isEmpty then (false, false)
47+
else (params.head.is(Given), params.head.is(Implicit))
48+
val make = MethodType.companion(isContextual = isContextual, isImplicit = isImplicit)
4949
if isJava then
5050
for param <- params do
5151
if param.info.isDirectRef(defn.ObjectClass) then param.info = defn.AnyType

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

Lines changed: 21 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ object Types {
427427
def isContextualMethod: Boolean = false
428428

429429
/** Is this a MethodType for which the parameters will not be used? */
430-
def hasErasedParams: Boolean = false
430+
def hasErasedParams(using Context): Boolean = false
431431

432432
/** Is this a match type or a higher-kinded abstraction of one?
433433
*/
@@ -1182,7 +1182,8 @@ object Types {
11821182

11831183
/** Remove all AnnotatedTypes wrapping this type.
11841184
*/
1185-
def stripAnnots(using Context): Type = this
1185+
def stripAnnots(keep: Annotation => Context ?=> Boolean)(using Context): Type = this
1186+
final def stripAnnots(using Context): Type = stripAnnots(_ => false)
11861187

11871188
/** Strip TypeVars and Annotation and CapturingType wrappers */
11881189
def stripped(using Context): Type = this
@@ -1843,14 +1844,13 @@ object Types {
18431844
case mt: MethodType if !mt.isParamDependent =>
18441845
val formals1 = if (dropLast == 0) mt.paramInfos else mt.paramInfos dropRight dropLast
18451846
val isContextual = mt.isContextualMethod && !ctx.erasedTypes
1846-
val erasedParams = (if !ctx.erasedTypes then mt.erasedParams else List.fill(mt.paramInfos.size) { false }).dropRight(dropLast)
18471847
val result1 = mt.nonDependentResultApprox match {
18481848
case res: MethodType => res.toFunctionType(isJava)
18491849
case res => res
18501850
}
18511851
val funType = defn.FunctionOf(
18521852
formals1 mapConserve (_.translateFromRepeated(toArray = isJava)),
1853-
result1, isContextual, erasedParams)
1853+
result1, isContextual)
18541854
if alwaysDependent || mt.isResultDependent then RefinedType(funType, nme.apply, mt)
18551855
else funType
18561856
}
@@ -3623,7 +3623,7 @@ object Types {
36233623

36243624
def companion: LambdaTypeCompanion[ThisName, PInfo, This]
36253625

3626-
def erasedParams = List.fill(paramInfos.size)(false)
3626+
def erasedParams(using Context) = List.fill(paramInfos.size)(false)
36273627

36283628
/** The type `[tparams := paramRefs] tp`, where `tparams` can be
36293629
* either a list of type parameter symbols or a list of lambda parameters
@@ -3913,38 +3913,14 @@ object Types {
39133913
def companion: MethodTypeCompanion
39143914

39153915
final override def isImplicitMethod: Boolean =
3916-
companion.eq(ImplicitMethodType) ||
3917-
companion.isInstanceOf[ErasedImplicitMethodType] ||
3918-
isContextualMethod
3919-
final override def hasErasedParams: Boolean =
3920-
companion.isInstanceOf[ErasedMethodCompanion]
3916+
companion.eq(ImplicitMethodType) || isContextualMethod
3917+
final override def hasErasedParams(using Context): Boolean =
3918+
erasedParams.contains(true)
39213919
final override def isContextualMethod: Boolean =
3922-
companion.eq(ContextualMethodType) ||
3923-
companion.isInstanceOf[ErasedContextualMethodType]
3924-
3925-
override def erasedParams: List[Boolean] = companion match
3926-
case c: ErasedMethodCompanion => c.erasedParams
3927-
case _ => super.erasedParams
3928-
3929-
// Mark erased classes as erased parameters as well.
3930-
def markErasedClasses(using Context): MethodType =
3931-
val isErasedClass = paramInfos.map(_.isErasedClass)
3932-
if isErasedClass.contains(true) then companion match
3933-
case c: ErasedMethodCompanion =>
3934-
val erasedParams = c.erasedParams.zipWithConserve(isErasedClass) { (a, b) => a || b }
3935-
if erasedParams == c.erasedParams then this
3936-
else MethodType.companion(
3937-
isContextual = isContextualMethod,
3938-
isImplicit = isImplicitMethod,
3939-
erasedParams = erasedParams
3940-
)(paramNames)(paramInfosExp, resultTypeExp)
3941-
case _ =>
3942-
MethodType.companion(
3943-
isContextual = isContextualMethod,
3944-
isImplicit = isImplicitMethod,
3945-
erasedParams = isErasedClass
3946-
)(paramNames)(paramInfosExp, resultTypeExp)
3947-
else this
3920+
companion.eq(ContextualMethodType)
3921+
3922+
override def erasedParams(using Context): List[Boolean] =
3923+
paramInfos.map(p => p.hasAnnotation(defn.ErasedParamAnnot) || p.isErasedClass)
39483924

39493925
protected def prefixString: String = companion.prefixString
39503926
}
@@ -4041,7 +4017,7 @@ object Types {
40414017
tl => tl.integrate(params, resultType))
40424018
end fromSymbols
40434019

4044-
final def apply(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(using Context): MethodType =
4020+
def apply(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(using Context): MethodType =
40454021
checkValid(unique(new CachedMethodType(paramNames)(paramInfosExp, resultTypeExp, self)))
40464022

40474023
def checkValid(mt: MethodType)(using Context): mt.type = {
@@ -4056,25 +4032,14 @@ object Types {
40564032
}
40574033

40584034
object MethodType extends MethodTypeCompanion("MethodType") {
4059-
def companion(isContextual: Boolean = false, isImplicit: Boolean = false, erasedParams: List[Boolean] = Nil): MethodTypeCompanion =
4060-
val hasErased = erasedParams.contains(true)
4061-
if (isContextual)
4062-
if (hasErased) ErasedContextualMethodType(erasedParams) else ContextualMethodType
4063-
else if (isImplicit)
4064-
if (hasErased) ErasedImplicitMethodType(erasedParams) else ImplicitMethodType
4065-
else
4066-
if (hasErased) ErasedMethodType(erasedParams) else MethodType
4035+
def companion(isContextual: Boolean = false, isImplicit: Boolean = false): MethodTypeCompanion =
4036+
if (isContextual) ContextualMethodType
4037+
else if (isImplicit) ImplicitMethodType
4038+
else MethodType
40674039
}
4068-
private def erasedMt(t: String, erasedParams: List[Boolean]) =
4069-
s"Erased${t}(${erasedParams.map(if _ then "erased _" else "_").mkString(", ")})"
4070-
sealed abstract class ErasedMethodCompanion(prefixString: String, val erasedParams: List[Boolean])
4071-
extends MethodTypeCompanion(erasedMt(prefixString, erasedParams))
40724040

4073-
class ErasedMethodType(erasedParams: List[Boolean]) extends ErasedMethodCompanion("MethodType", erasedParams)
40744041
object ContextualMethodType extends MethodTypeCompanion("ContextualMethodType")
4075-
class ErasedContextualMethodType(erasedParams: List[Boolean]) extends ErasedMethodCompanion("ContextualMethodType", erasedParams)
40764042
object ImplicitMethodType extends MethodTypeCompanion("ImplicitMethodType")
4077-
class ErasedImplicitMethodType(erasedParams: List[Boolean]) extends ErasedMethodCompanion("ImplicitMethodType", erasedParams)
40784043

40794044
/** A ternary extractor for MethodType */
40804045
object MethodTpe {
@@ -5289,7 +5254,10 @@ object Types {
52895254
override def stripTypeVar(using Context): Type =
52905255
derivedAnnotatedType(parent.stripTypeVar, annot)
52915256

5292-
override def stripAnnots(using Context): Type = parent.stripAnnots
5257+
override def stripAnnots(keep: Annotation => (Context) ?=> Boolean)(using Context): Type =
5258+
val p = parent.stripAnnots(keep)
5259+
if keep(annot) then derivedAnnotatedType(p, annot)
5260+
else p
52935261

52945262
override def stripped(using Context): Type = parent.stripped
52955263

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

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,7 @@ class TastyPrinter(bytes: Array[Byte]) {
137137
printTree()
138138
while (currentAddr.index < end.index && !isModifierTag(nextByte)) { printTree(); printName(); }
139139
// read tags
140-
until(end) {
141-
val tag = readByte()
142-
newLine()
143-
sb.append(" ").append(astTagToString(tag))
144-
if tag == ERASED then // ERASED comes with erased parameter flags
145-
val erasedParams = readBits().map(b => if b then "erased _" else "_")
146-
sb.append(s"(${erasedParams.mkString(", ")})")
147-
}
140+
printTrees()
148141
case PARAMtype =>
149142
printNat(); printNat()
150143
case _ =>

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import config.Config
1919
import collection.mutable
2020
import reporting.{Profile, NoProfile}
2121
import dotty.tools.tasty.TastyFormat.ASTsSection
22-
import dotty.tools.dotc.transform.TypeUtils.isErasedClass
2322

2423
object TreePickler:
2524
class StackSizeExceeded(val mdef: tpd.MemberDef) extends Exception
@@ -288,7 +287,6 @@ class TreePickler(pickler: TastyPickler) {
288287
var mods = EmptyFlags
289288
if tpe.isContextualMethod then mods |= Given
290289
else if tpe.isImplicitMethod then mods |= Implicit
291-
if tpe.hasErasedParams then mods |= Erased
292290
pickleMethodic(METHODtype, tpe, mods)
293291
case tpe: ParamRef =>
294292
assert(pickleParamRef(tpe), s"orphan parameter reference: $tpe")
@@ -303,10 +301,7 @@ class TreePickler(pickler: TastyPickler) {
303301
tpe.paramNames.lazyZip(tpe.paramInfos).foreach { (name, tpe) =>
304302
pickleType(tpe); pickleName(name)
305303
}
306-
if (mods != EmptyFlags) pickleFlags(mods &~ Flags.Erased, tpe.isTermLambda)
307-
if mods.is(Erased) then
308-
writeByte(ERASED)
309-
writeBits(tpe.erasedParams)
304+
if (mods != EmptyFlags) pickleFlags(mods, tpe.isTermLambda)
310305
}
311306
}
312307

0 commit comments

Comments
 (0)