Skip to content

Commit 824c763

Browse files
committed
Remove ErasedMethodCompanions
We don't really need them, as we can fully rely on erased parameter annotations. There is however a special case needed attention, where we infer the annotations of the type: def use(f: (erased Int) => Int): Int = f(5) val v = use { x => 5 } Here `x` will be inferred to `Int @erasedParam`, which makes it an erased parameter, though the user might have not intended to do. We strip the annotated here, unless the user explicitly writes `erased x`.
1 parent 87b804b commit 824c763

File tree

5 files changed

+27
-56
lines changed

5 files changed

+27
-56
lines changed

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

Lines changed: 16 additions & 42 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
@@ -3913,26 +3914,14 @@ object Types {
39133914
def companion: MethodTypeCompanion
39143915

39153916
final override def isImplicitMethod: Boolean =
3916-
companion.eq(ImplicitMethodType) ||
3917-
companion.eq(ErasedImplicitMethodType) ||
3918-
isContextualMethod
3919-
final override def hasErasedParams: Boolean =
3920-
companion.isInstanceOf[ErasedMethodCompanion]
3917+
companion.eq(ImplicitMethodType) || isContextualMethod
3918+
final override def hasErasedParams(using Context): Boolean =
3919+
erasedParams.contains(true)
39213920
final override def isContextualMethod: Boolean =
3922-
companion.eq(ContextualMethodType) ||
3923-
companion.eq(ErasedContextualMethodType)
3924-
3925-
override def erasedParams(using Context): List[Boolean] = companion match
3926-
case c: ErasedMethodCompanion => c.erasedParams(paramInfos)
3927-
case _ => super.erasedParams
3928-
3929-
/** Returns the corresponding companion, but without erased parameters */
3930-
final def companionWithoutErased = companion match
3931-
case ErasedImplicitMethodType => ImplicitMethodType
3932-
case ErasedContextualMethodType => ContextualMethodType
3933-
case ErasedMethodType => MethodType
3934-
case actual => actual
3921+
companion.eq(ContextualMethodType)
39353922

3923+
override def erasedParams(using Context): List[Boolean] =
3924+
paramInfos.map(p => p.hasAnnotation(defn.ErasedParamAnnot) || p.isErasedClass)
39363925

39373926
protected def prefixString: String = companion.prefixString
39383927
}
@@ -4046,31 +4035,13 @@ object Types {
40464035
object MethodType extends MethodTypeCompanion("MethodType") {
40474036
def companion(isContextual: Boolean = false, isImplicit: Boolean = false, erasedParams: List[Boolean] = Nil): MethodTypeCompanion =
40484037
val hasErased = erasedParams.contains(true)
4049-
if (isContextual)
4050-
if (hasErased) ErasedContextualMethodType else ContextualMethodType
4051-
else if (isImplicit)
4052-
if (hasErased) ErasedImplicitMethodType else ImplicitMethodType
4053-
else
4054-
if (hasErased) ErasedMethodType else MethodType
4055-
}
4056-
sealed abstract class ErasedMethodCompanion(withoutErased: MethodTypeCompanion)
4057-
extends MethodTypeCompanion("Erased" + withoutErased.prefixString) {
4058-
4059-
override def apply(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(using Context): MethodType =
4060-
val mt = super.apply(paramNames)(paramInfosExp, resultTypeExp)
4061-
// assert(erasedParams(mt.paramInfos).contains(true), s"$mt must contain an erased parameter")
4062-
if erasedParams(mt.paramInfos).contains(true) then mt
4063-
else withoutErased(paramNames)(paramInfosExp, resultTypeExp)
4064-
4065-
def erasedParams(paramsInfo: List[Type])(using Context) =
4066-
paramsInfo.map(p => p.hasAnnotation(defn.ErasedParamAnnot) || p.isErasedClass)
4038+
if (isContextual) ContextualMethodType
4039+
else if (isImplicit) ImplicitMethodType
4040+
else MethodType
40674041
}
40684042

4069-
object ErasedMethodType extends ErasedMethodCompanion(MethodType)
40704043
object ContextualMethodType extends MethodTypeCompanion("ContextualMethodType")
4071-
object ErasedContextualMethodType extends ErasedMethodCompanion(ContextualMethodType)
40724044
object ImplicitMethodType extends MethodTypeCompanion("ImplicitMethodType")
4073-
object ErasedImplicitMethodType extends ErasedMethodCompanion(ImplicitMethodType)
40744045

40754046
/** A ternary extractor for MethodType */
40764047
object MethodTpe {
@@ -5285,7 +5256,10 @@ object Types {
52855256
override def stripTypeVar(using Context): Type =
52865257
derivedAnnotatedType(parent.stripTypeVar, annot)
52875258

5288-
override def stripAnnots(using Context): Type = parent.stripAnnots
5259+
override def stripAnnots(keep: Annotation => (Context) ?=> Boolean)(using Context): Type =
5260+
val p = parent.stripAnnots(keep)
5261+
if keep(annot) then derivedAnnotatedType(p, annot)
5262+
else p
52895263

52905264
override def stripped(using Context): Type = parent.stripped
52915265

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -401,11 +401,7 @@ class TreeUnpickler(reader: TastyReader,
401401
readMethodic(_ => PolyType, _.toTypeName)
402402
case METHODtype =>
403403
def methodTypeCompanion(mods: FlagSet): MethodTypeCompanion =
404-
if mods.is(Erased) then
405-
if mods.is(Implicit) then ErasedImplicitMethodType
406-
else if mods.is(Given) then ErasedContextualMethodType
407-
else ErasedMethodType
408-
else if mods.is(Implicit) then ImplicitMethodType
404+
if mods.is(Implicit) then ImplicitMethodType
409405
else if mods.is(Given) then ContextualMethodType
410406
else MethodType
411407
readMethodic(methodTypeCompanion, _.toTermName)

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,7 @@ object ContextFunctionResults:
7373
case tp: MethodOrPoly =>
7474
tp.derivedLambdaType(resType = integrateContextResults(tp.resType, crCount))
7575
case defn.ContextFunctionType(argTypes, resType, erasedParams) =>
76-
val methodType: MethodTypeCompanion =
77-
if erasedParams.contains(true) then ErasedMethodType else MethodType
78-
methodType(argTypes, integrateContextResults(resType, crCount - 1))
76+
MethodType(argTypes, integrateContextResults(resType, crCount - 1))
7977

8078
/** The total number of parameters of method `sym`, not counting
8179
* erased parameters, but including context result parameters.

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import ast.tpd
1313
import SymUtils._
1414
import config.Feature
1515
import Decorators.*
16-
import dotty.tools.dotc.core.Types.ErasedMethodCompanion
1716
import dotty.tools.dotc.core.Types.MethodType
1817

1918
/** This phase makes all erased term members of classes private so that they cannot

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,16 +1293,18 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
12931293
* If both attempts fail, return `NoType`.
12941294
*/
12951295
def inferredFromTarget(
1296-
param: untpd.ValDef, formal: Type, calleeType: Type, paramIndex: Name => Int)(using Context): Type =
1296+
param: untpd.ValDef, formal: Type, calleeType: Type, isErased: Boolean, paramIndex: Name => Int)(using Context): Type =
12971297
val target = calleeType.widen match
12981298
case mtpe: MethodType =>
12991299
val pos = paramIndex(param.name)
13001300
if pos < mtpe.paramInfos.length then
1301-
mtpe.paramInfos(pos)
1301+
val tp = mtpe.paramInfos(pos)
13021302
// This works only if vararg annotations match up.
13031303
// See neg/i14367.scala for an example where the inferred type is mispredicted.
13041304
// Nevertheless, the alternative would be to give up completely, so this is
13051305
// defensible.
1306+
// Strip inferred erased annotation, to avoid accidentally inferring erasedness
1307+
if !isErased then tp.stripAnnots(_.symbol != defn.ErasedParamAnnot) else tp
13061308
else NoType
13071309
case _ => NoType
13081310
if target.exists then formal <:< target
@@ -1534,11 +1536,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
15341536
// If the expected formal is a TypeBounds wildcard argument with Nothing as lower bound,
15351537
// try to prioritize inferring from target. See issue 16405 (tests/run/16405.scala)
15361538
val paramType =
1539+
// Strip inferred erased annotation, to avoid accidentally inferring erasedness
1540+
val formal0 = if !isErased then formal.stripAnnots(_.symbol != defn.ErasedParamAnnot) else formal
15371541
if knownFormal && !isBottomFromWildcard then
1538-
formal
1542+
formal0
15391543
else
1540-
inferredFromTarget(param, formal, calleeType, paramIndex).orElse(
1541-
if knownFormal then formal
1544+
inferredFromTarget(param, formal, calleeType, isErased, paramIndex).orElse(
1545+
if knownFormal then formal0
15421546
else errorType(AnonymousFunctionMissingParamType(param, tree, formal), param.srcPos)
15431547
)
15441548
val paramTpt = untpd.TypedSplice(

0 commit comments

Comments
 (0)