Skip to content

Commit 4a0e514

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 83586fd commit 4a0e514

File tree

85 files changed

+266
-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

+266
-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
@@ -444,6 +444,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
444444
else if (tpw isRef defn.DoubleClass) Literal(Constant(0d))
445445
else if (tpw isRef defn.ByteClass) Literal(Constant(0.toByte))
446446
else if (tpw isRef defn.ShortClass) Literal(Constant(0.toShort))
447+
else if (tpw.isPhantom) Literal(Constant(null)).withType(tpw)
447448
else Literal(Constant(null)).select(defn.Any_asInstanceOf).appliedToType(tpe)
448449
}
449450

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

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

11751175
val any = enterCompleteClassSymbol(cls, tpnme.Any, Protected | Final | NoInitsTrait, Nil)
11761176
val nothing = enterCompleteClassSymbol(cls, tpnme.Nothing, Protected | Final | NoInitsTrait, List(any.typeRef))
1177-
enterMethod(cls, nme.assume_, ExprType(nothing.typeRef), Protected | Final | Method)
1177+
enterMethod(cls, nme.assume_, ExprType(nothing.typeRef), Protected | Final | Method | Unused)
11781178

11791179
cls
11801180
}
11811181
lazy val Phantom_AnyClass = PhantomClass.unforcedDecls.find(_.name eq tpnme.Any).asClass
11821182
lazy val Phantom_NothingClass = PhantomClass.unforcedDecls.find(_.name eq tpnme.Nothing).asClass
1183-
lazy val Phantom_assume = PhantomClass.unforcedDecls.find(_.name eq nme.assume_)
11841183

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

1188-
11891187
lazy val ErasedPhantomType: TypeRef = ctx.requiredClassRef("dotty.runtime.ErasedPhantom")
1190-
def ErasedPhantomClass(implicit ctx: Context) = ErasedPhantomType.symbol.asClass
1191-
1192-
def ErasedPhantom_UNIT(implicit ctx: Context) = ErasedPhantomClass.linkedClass.requiredValue("UNIT")
1193-
11941188
}

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 =>
@@ -525,8 +522,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
525522
}
526523
if (defn.isSyntheticFunctionClass(sym))
527524
sigName(defn.erasedFunctionType(sym))
528-
else if (defn.isPhantomTerminalClass(tp.symbol))
529-
sigName(PhantomErasure.erasedPhantomType)
530525
else
531526
normalizeClass(sym.asClass).fullName.asTypeName
532527
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,
@@ -691,7 +674,4 @@ object Erasure {
691674

692675
def takesBridges(sym: Symbol)(implicit ctx: Context) =
693676
sym.isClass && !sym.is(Flags.Trait | Flags.Package)
694-
695-
private def wasPhantom(tp: Type)(implicit ctx: Context): Boolean =
696-
tp.widenDealias.classSymbol eq defn.ErasedPhantomClass
697677
}

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

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

180-
override def transformValDef(vdef: tpd.ValDef)(implicit ctx: Context): tpd.Tree = {
181-
if (vdef.tpt.tpe.isPhantom) {
182-
if (vdef.symbol.is(Mutable)) ctx.error("var fields cannot have Phantom types", vdef.pos)
183-
else if (vdef.symbol.hasAnnotation(defn.VolatileAnnot)) ctx.error("Phantom fields cannot be @volatile", vdef.pos)
184-
}
185-
vdef
186-
}
187-
188180
override def transformStats(trees: List[Tree])(implicit ctx: Context): List[Tree] =
189181
ast.Trees.flatten(reorderAndComplete(trees)(ctx.withPhase(thisPhase.next)))
190182

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

@@ -184,8 +183,6 @@ object Simplify {
184183
sym.owner.is(CaseClass) &&
185184
sym.name.isSelectorName &&
186185
!sym.info.decls.exists(_.is(Mutable | Lazy)) // Conservatively covers case class A(var x: Int)
187-
val isErasedPhantom = PhantomErasure.isErasedPhantom(sym)
188-
189-
isImmutableGetter || isCaseAccessor || isProductAccessor || isErasedPhantom
186+
isImmutableGetter || isCaseAccessor || isProductAccessor
190187
}
191188
}

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -496,12 +496,10 @@ object Checking {
496496
case param :: params =>
497497
if (param.is(Mutable))
498498
ctx.error(ValueClassParameterMayNotBeAVar(clazz, param), param.pos)
499-
if (param.info.isPhantom)
500-
ctx.error("First parameter of value class must not be phantom", param.pos)
501-
else if (param.is(Unused))
502-
ctx.error("First parameter of value class cannot be `unused`", param.pos)
499+
if (param.is(Unused))
500+
ctx.error("value class first parameter cannot be `unused`", param.pos)
503501
else {
504-
for (p <- params if !(p.info.isPhantom || p.is(Unused)))
502+
for (p <- params if !p.is(Unused))
505503
ctx.error("value class can only have one non `unused` parameter", p.pos)
506504
}
507505
case Nil =>

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class FromTastyTests extends ParallelTesting {
4646
"tcpoly_ticket2096.scala",
4747
"t247.scala",
4848
"i3067.scala",
49+
"phantom-Eq.scala",
50+
"phantom-Evidence.scala",
4951
)
5052
)
5153
step1.checkCompile() // Compile all files to generate the class files with tasty
@@ -87,6 +89,32 @@ class FromTastyTests extends ParallelTesting {
8789
"t3452f.scala",
8890
"t8395.scala",
8991
"t3613.scala",
92+
"phantom-methods-12.scala",
93+
"phantom-methods-8.scala",
94+
"phantom-methods-2.scala",
95+
"phantom-methods-9.scala",
96+
"phantom-methods-13.scala",
97+
"phantom-methods-14.scala",
98+
"phantom-decls-4.scala",
99+
"phantom-self-1.scala",
100+
"phantom-val-2.scala",
101+
"phantom-3.scala",
102+
"phantom-OnHList.scala",
103+
"phantom-1.scala",
104+
"phantom-4.scala",
105+
"phantom-5.scala",
106+
"phantom-methods-1.scala",
107+
"phantom-val.scala",
108+
"phantom-decls-2.scala",
109+
"phantom-assume-1.scala",
110+
"phantom-methods-10.scala",
111+
"phantom-methods-7.scala",
112+
"phantom-methods-6.scala",
113+
"phantom-methods-11.scala",
114+
"phantom-erased-methods.scala",
115+
"phantom-methods-5.scala",
116+
"phantom-2.scala",
117+
"phantom-param-accessor.scala",
90118
)
91119
)
92120
step1.checkCompile() // Compile all files to generate the class files with tasty

0 commit comments

Comments
 (0)