Skip to content

Commit b567b8d

Browse files
committed
Make all phantoms unused
This removes the necesity of erasing phantoms. This process is done by the erasure of `unused`.
1 parent 8d07271 commit b567b8d

File tree

85 files changed

+267
-493
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+267
-493
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ class Compiler {
8080
new ShortcutImplicits, // Allow implicit functions without creating closures
8181
new CrossCastAnd, // Normalize selections involving intersection types.
8282
new Splitter) :: // Expand selections involving union types into conditionals
83-
List(new PhantomArgLift, // Extracts the evaluation of phantom arguments placing them before the call.
84-
new UnusedDecls, // Removes all unused defs and vals decls (except for parameters)
83+
List(new UnusedDecls, // Removes all unused defs and vals decls (except for parameters)
8584
new VCInlineMethods, // Inlines calls to value class methods
8685
new SeqLiterals, // Express vararg arguments as arrays
8786
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
442442
else if (tpw isRef defn.DoubleClass) Literal(Constant(0d))
443443
else if (tpw isRef defn.ByteClass) Literal(Constant(0.toByte))
444444
else if (tpw isRef defn.ShortClass) Literal(Constant(0.toShort))
445+
else if (tpw.isPhantom) Literal(Constant(null)).withType(tpw)
445446
else Literal(Constant(null)).select(defn.Any_asInstanceOf).appliedToType(tpe)
446447
}
447448

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,21 +1198,15 @@ class Definitions {
11981198

11991199
val any = enterCompleteClassSymbol(cls, tpnme.Any, Protected | Final | NoInitsTrait, Nil)
12001200
val nothing = enterCompleteClassSymbol(cls, tpnme.Nothing, Protected | Final | NoInitsTrait, List(any.typeRef))
1201-
enterMethod(cls, nme.assume_, ExprType(nothing.typeRef), Protected | Final | Method)
1201+
enterMethod(cls, nme.assume_, ExprType(nothing.typeRef), Protected | Final | Method | Unused)
12021202

12031203
cls
12041204
}
12051205
lazy val Phantom_AnyClass = PhantomClass.unforcedDecls.find(_.name eq tpnme.Any).asClass
12061206
lazy val Phantom_NothingClass = PhantomClass.unforcedDecls.find(_.name eq tpnme.Nothing).asClass
1207-
lazy val Phantom_assume = PhantomClass.unforcedDecls.find(_.name eq nme.assume_)
12081207

12091208
/** If the symbol is of the class scala.Phantom.Any or scala.Phantom.Nothing */
12101209
def isPhantomTerminalClass(sym: Symbol) = (sym eq Phantom_AnyClass) || (sym eq Phantom_NothingClass)
12111210

1212-
12131211
lazy val ErasedPhantomType: TypeRef = ctx.requiredClassRef("dotty.runtime.ErasedPhantom")
1214-
def ErasedPhantomClass(implicit ctx: Context) = ErasedPhantomType.symbol.asClass
1215-
1216-
def ErasedPhantom_UNIT(implicit ctx: Context) = ErasedPhantomClass.linkedClass.requiredValue("UNIT")
1217-
12181212
}

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

Lines changed: 0 additions & 33 deletions
This file was deleted.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) {
8484
* to the parameter part of this signature.
8585
*/
8686
def prepend(params: List[Type], isJava: Boolean)(implicit ctx: Context) =
87-
Signature(params.collect { case p if !p.isPhantom => sigName(p, isJava) } ++ paramsSig, resSig)
87+
Signature(params.map(p => sigName(p, isJava)) ++ paramsSig, resSig)
8888

8989
/** A signature is under-defined if its paramsSig part contains at least one
9090
* `tpnme.Uninstantiated`. Under-defined signatures arise when taking a signature

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
380380
else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp)
381381
else if (sym == defn.ArrayClass) apply(tp.appliedTo(TypeBounds.empty)) // i966 shows that we can hit a raw Array type.
382382
else if (defn.isSyntheticFunctionClass(sym)) defn.erasedFunctionType(sym)
383-
else if (defn.isPhantomTerminalClass(sym)) PhantomErasure.erasedPhantomType
383+
else if (defn.isPhantomTerminalClass(sym)) defn.ErasedPhantomType
384384
else if (sym eq defn.PhantomClass) defn.ObjectType // To erase the definitions of Phantom.{assume, Any, Nothing}
385385
else eraseNormalClassRef(tp)
386386
case tp: AppliedType =>
@@ -401,10 +401,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
401401
case tp: MethodType =>
402402
def paramErasure(tpToErase: Type) =
403403
erasureFn(tp.isJavaMethod, semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
404-
val (names, formals0) =
405-
if (tp.isUnusedMethod) (Nil, Nil)
406-
else if (tp.paramInfos.exists(_.isPhantom)) tp.paramNames.zip(tp.paramInfos).filterNot(_._2.isPhantom).unzip
407-
else (tp.paramNames, tp.paramInfos)
404+
val (names, formals0) = if (tp.isUnusedMethod) (Nil, Nil) else (tp.paramNames, tp.paramInfos)
408405
val formals = formals0.mapConserve(paramErasure)
409406
eraseResult(tp.resultType) match {
410407
case rt: MethodType =>
@@ -527,8 +524,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
527524
}
528525
if (defn.isSyntheticFunctionClass(sym))
529526
sigName(defn.erasedFunctionType(sym))
530-
else if (defn.isPhantomTerminalClass(tp.symbol))
531-
sigName(PhantomErasure.erasedPhantomType)
532527
else
533528
normalizeClass(sym.asClass).fullName.asTypeName
534529
case tp: AppliedType =>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
131131
// Produce aligned accessors and constructor parameters. We have to adjust
132132
// for any outer parameters, which are last in the sequence of original
133133
// parameter accessors but come first in the constructor parameter list.
134-
val accessors = cls.paramAccessors.filterNot(x => x.isSetter || x.info.resultType.classSymbol == defn.ErasedPhantomClass)
134+
val accessors = cls.paramAccessors.filterNot(x => x.isSetter)
135135
val vparamsWithOuterLast = vparams match {
136136
case vparam :: rest if vparam.name == nme.OUTER => rest ::: vparam :: Nil
137137
case _ => vparams

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

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import ValueClasses._
2828
import TypeUtils._
2929
import ExplicitOuter._
3030
import core.Mode
31-
import core.PhantomErasure
3231
import reporting.trace
3332

3433
class Erasure extends Phase with DenotTransformer {
@@ -213,8 +212,6 @@ object Erasure {
213212
val tree1 =
214213
if (tree.tpe isRef defn.NullClass)
215214
adaptToType(tree, underlying)
216-
else if (wasPhantom(underlying))
217-
PhantomErasure.erasedParameterRef
218215
else if (!(tree.tpe <:< tycon)) {
219216
assert(!(tree.tpe.typeSymbol.isPrimitiveValueClass))
220217
val nullTree = Literal(Constant(null))
@@ -437,16 +434,9 @@ object Erasure {
437434
}
438435
}
439436

440-
if ((origSym eq defn.Phantom_assume) || (origSym.is(Flags.ParamAccessor) && wasPhantom(pt)))
441-
PhantomErasure.erasedAssume
442-
else recur(typed(tree.qualifier, AnySelectionProto))
437+
recur(typed(tree.qualifier, AnySelectionProto))
443438
}
444439

445-
override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): tpd.Tree =
446-
if (tree.symbol eq defn.Phantom_assume) PhantomErasure.erasedAssume
447-
else if (tree.symbol.is(Flags.Param) && wasPhantom(tree.typeOpt)) PhantomErasure.erasedParameterRef
448-
else super.typedIdent(tree, pt)
449-
450440
override def typedThis(tree: untpd.This)(implicit ctx: Context): Tree =
451441
if (tree.symbol == ctx.owner.lexicallyEnclosingClass || tree.symbol.isStaticOwner) promote(tree)
452442
else {
@@ -507,11 +497,9 @@ object Erasure {
507497
.withType(defn.ArrayOf(defn.ObjectType))
508498
args0 = bunchedArgs :: Nil
509499
}
510-
// Arguments are phantom if an only if the parameters are phantom, guaranteed by the separation of type lattices
511-
val args1 = args0.filterConserve(arg => !wasPhantom(arg.typeOpt))
512-
assert(args1 hasSameLengthAs mt.paramInfos)
513-
val args2 = args1.zipWithConserve(mt.paramInfos)(typedExpr)
514-
untpd.cpy.Apply(tree)(fun1, args2) withType mt.resultType
500+
assert(args0 hasSameLengthAs mt.paramInfos)
501+
val args1 = args0.zipWithConserve(mt.paramInfos)(typedExpr)
502+
untpd.cpy.Apply(tree)(fun1, args1) withType mt.resultType
515503
case _ =>
516504
throw new MatchError(i"tree $tree has unexpected type of function ${fun1.tpe.widen}, was ${fun.typeOpt.widen}")
517505
}
@@ -572,11 +560,6 @@ object Erasure {
572560
rhs1 = untpd.Block(paramDefs, rhs1)
573561
}
574562
vparamss1 = vparamss1.mapConserve(_.filterConserve(!_.symbol.is(Flags.Unused)))
575-
vparamss1 = vparamss1.mapConserve(_.filterConserve(vparam => !wasPhantom(vparam.tpe)))
576-
if (sym.is(Flags.ParamAccessor) && wasPhantom(ddef.tpt.tpe)) {
577-
sym.resetFlag(Flags.ParamAccessor)
578-
rhs1 = PhantomErasure.erasedParameterRef
579-
}
580563
val ddef1 = untpd.cpy.DefDef(ddef)(
581564
tparams = Nil,
582565
vparamss = vparamss1,
@@ -703,7 +686,4 @@ object Erasure {
703686

704687
def takesBridges(sym: Symbol)(implicit ctx: Context) =
705688
sym.isClass && !sym.is(Flags.Trait | Flags.Package)
706-
707-
private def wasPhantom(tp: Type)(implicit ctx: Context): Boolean =
708-
tp.widenDealias.classSymbol eq defn.ErasedPhantomClass
709689
}

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,6 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase =>
161161
} else ddef
162162
}
163163

164-
override def transformValDef(vdef: tpd.ValDef)(implicit ctx: Context): tpd.Tree = {
165-
if (vdef.tpt.tpe.isPhantom) {
166-
if (vdef.symbol.is(Mutable)) ctx.error("var fields cannot have Phantom types", vdef.pos)
167-
else if (vdef.symbol.hasAnnotation(defn.VolatileAnnot)) ctx.error("Phantom fields cannot be @volatile", vdef.pos)
168-
}
169-
vdef
170-
}
171-
172164
override def transformStats(trees: List[Tree])(implicit ctx: Context): List[Tree] =
173165
ast.Trees.flatten(reorderAndComplete(trees)(ctx.withPhase(thisPhase.next)))
174166

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ import Decorators._
107107
if (sym eq defn.NothingClass) Throw(Literal(Constant(null)))
108108
else if (sym eq defn.NullClass) Literal(Constant(null))
109109
else if (sym eq defn.BoxedUnitClass) ref(defn.BoxedUnit_UNIT)
110-
else if (sym eq defn.ErasedPhantomClass) ref(defn.ErasedPhantom_UNIT)
111110
else {
112111
assert(false, sym + " has no erased bottom tree")
113112
EmptyTree
@@ -120,11 +119,8 @@ import Decorators._
120119
def adaptToField(tree: Tree): Tree =
121120
if (tree.isEmpty) tree else tree.ensureConforms(field.info.widen)
122121

123-
def isErasableBottomField(cls: Symbol): Boolean = {
124-
// TODO: For Scala.js, return false if this field is in a js.Object unless it is an ErasedPhantomClass.
125-
!field.isVolatile &&
126-
((cls eq defn.NothingClass) || (cls eq defn.NullClass) || (cls eq defn.BoxedUnitClass) || (cls eq defn.ErasedPhantomClass))
127-
}
122+
def isErasableBottomField(cls: Symbol): Boolean =
123+
!field.isVolatile && ((cls eq defn.NothingClass) || (cls eq defn.NullClass) || (cls eq defn.BoxedUnitClass))
128124

129125
if (sym.isGetter) {
130126
var rhs = tree.rhs.changeOwnerAfter(sym, field, thisPhase)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ class SyntheticMethods(thisPhase: DenotTransformer) {
163163
val thatAsClazz = ctx.newSymbol(ctx.owner, nme.x_0, Synthetic, clazzType, coord = ctx.owner.pos) // x$0
164164
def wildcardAscription(tp: Type) = Typed(Underscore(tp), TypeTree(tp))
165165
val pattern = Bind(thatAsClazz, wildcardAscription(clazzType)) // x$0 @ (_: C)
166-
val comparisons = accessors collect { case accessor if !accessor.info.isPhantom =>
166+
val comparisons = accessors map { accessor =>
167167
This(clazz).select(accessor).select(defn.Any_==).appliedTo(ref(thatAsClazz).select(accessor)) }
168168
val rhs = // this.x == this$0.x && this.y == x$0.y
169169
if (comparisons.isEmpty) Literal(Constant(true)) else comparisons.reduceLeft(_ and _)

compiler/src/dotty/tools/dotc/transform/localopt/Simplify.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import core.NameOps._
1111
import transform.MegaPhase.MiniPhase
1212
import config.Printers.simplify
1313
import ast.tpd
14-
import dotty.tools.dotc.core.PhantomErasure
1514

1615
import scala.annotation.tailrec
1716

@@ -170,8 +169,6 @@ object Simplify {
170169
sym.owner.is(CaseClass) &&
171170
sym.name.isSelectorName &&
172171
!sym.info.decls.exists(_.is(Mutable | Lazy)) // Conservatively covers case class A(var x: Int)
173-
val isErasedPhantom = PhantomErasure.isErasedPhantom(sym)
174-
175-
isImmutableGetter || isCaseAccessor || isProductAccessor || isErasedPhantom
172+
isImmutableGetter || isCaseAccessor || isProductAccessor
176173
}
177174
}

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -502,12 +502,10 @@ object Checking {
502502
case param :: params =>
503503
if (param.is(Mutable))
504504
ctx.error(ValueClassParameterMayNotBeAVar(clazz, param), param.pos)
505-
if (param.info.isPhantom)
506-
ctx.error("First parameter of value class must not be phantom", param.pos)
507-
else if (param.is(Unused))
508-
ctx.error("First parameter of value class cannot be `unused`", param.pos)
505+
if (param.is(Unused))
506+
ctx.error("value class first parameter cannot be `unused`", param.pos)
509507
else {
510-
for (p <- params if !(p.info.isPhantom || p.is(Unused)))
508+
for (p <- params if !p.is(Unused))
511509
ctx.error("value class can only have one non `unused` parameter", p.pos)
512510
}
513511
case Nil =>

compiler/test/dotty/tools/dotc/FromTastyTests.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class FromTastyTests extends ParallelTesting {
8383

8484
// Infinite compilation
8585
"t3612.scala",
86+
87+
"phantom-Eq.scala",
88+
"phantom-Evidence.scala",
8689
)
8790
)
8891
step1.checkCompile() // Compile all files to generate the class files with tasty
@@ -144,6 +147,32 @@ class FromTastyTests extends ParallelTesting {
144147
"unused-21.scala",
145148
"unused-23.scala",
146149
"unused-value-class.scala",
150+
"phantom-methods-12.scala",
151+
"phantom-methods-8.scala",
152+
"phantom-methods-2.scala",
153+
"phantom-methods-9.scala",
154+
"phantom-methods-13.scala",
155+
"phantom-methods-14.scala",
156+
"phantom-decls-4.scala",
157+
"phantom-self-1.scala",
158+
"phantom-val-2.scala",
159+
"phantom-3.scala",
160+
"phantom-OnHList.scala",
161+
"phantom-1.scala",
162+
"phantom-4.scala",
163+
"phantom-5.scala",
164+
"phantom-methods-1.scala",
165+
"phantom-val.scala",
166+
"phantom-decls-2.scala",
167+
"phantom-assume-1.scala",
168+
"phantom-methods-10.scala",
169+
"phantom-methods-7.scala",
170+
"phantom-methods-6.scala",
171+
"phantom-methods-11.scala",
172+
"phantom-erased-methods.scala",
173+
"phantom-methods-5.scala",
174+
"phantom-2.scala",
175+
"phantom-param-accessor.scala",
147176
)
148177
)
149178
step1.checkCompile() // Compile all files to generate the class files with tasty

0 commit comments

Comments
 (0)