Skip to content

Commit 391faf7

Browse files
committed
Make all phantoms unused
1 parent bd4b6dd commit 391faf7

File tree

80 files changed

+217
-452
lines changed

Some content is hidden

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

80 files changed

+217
-452
lines changed

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

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

10891089
val any = enterCompleteClassSymbol(cls, tpnme.Any, Protected | Final | NoInitsTrait, Nil)
10901090
val nothing = enterCompleteClassSymbol(cls, tpnme.Nothing, Protected | Final | NoInitsTrait, List(any.typeRef))
1091-
enterMethod(cls, nme.assume_, ExprType(nothing.typeRef), Protected | Final | Method)
1091+
enterMethod(cls, nme.assume_, ExprType(nothing.typeRef), Protected | Final | Method | Unused)
10921092

10931093
cls
10941094
}
10951095
lazy val Phantom_AnyClass = PhantomClass.unforcedDecls.find(_.name eq tpnme.Any).asClass
10961096
lazy val Phantom_NothingClass = PhantomClass.unforcedDecls.find(_.name eq tpnme.Nothing).asClass
1097-
lazy val Phantom_assume = PhantomClass.unforcedDecls.find(_.name eq nme.assume_)
10981097

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

1102-
11031101
lazy val ErasedPhantomType: TypeRef = ctx.requiredClassRef("dotty.runtime.ErasedPhantom")
1104-
def ErasedPhantomClass(implicit ctx: Context) = ErasedPhantomType.symbol.asClass
1105-
1106-
def ErasedPhantom_UNIT(implicit ctx: Context) = ErasedPhantomClass.linkedClass.requiredValue("UNIT")
1107-
11081102
}

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
@@ -378,7 +378,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
378378
else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp)
379379
else if (sym == defn.ArrayClass) apply(tp.appliedTo(TypeBounds.empty)) // i966 shows that we can hit a raw Array type.
380380
else if (defn.isSyntheticFunctionClass(sym)) defn.erasedFunctionType(sym)
381-
else if (defn.isPhantomTerminalClass(sym)) PhantomErasure.erasedPhantomType
381+
else if (defn.isPhantomTerminalClass(sym)) defn.ErasedPhantomType
382382
else if (sym eq defn.PhantomClass) defn.ObjectType // To erase the definitions of Phantom.{assume, Any, Nothing}
383383
else eraseNormalClassRef(tp)
384384
case tp: AppliedType =>
@@ -399,10 +399,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
399399
case tp: MethodType =>
400400
def paramErasure(tpToErase: Type) =
401401
erasureFn(tp.isJavaMethod, semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
402-
val (names, formals0) =
403-
if (tp.isUnusedMethod) (Nil, Nil)
404-
else if (tp.paramInfos.exists(_.isPhantom)) tp.paramNames.zip(tp.paramInfos).filterNot(_._2.isPhantom).unzip
405-
else (tp.paramNames, tp.paramInfos)
402+
val (names, formals0) = if (tp.isUnusedMethod) (Nil, Nil) else (tp.paramNames, tp.paramInfos)
406403
val formals = formals0.mapConserve(paramErasure)
407404
eraseResult(tp.resultType) match {
408405
case rt: MethodType =>
@@ -520,8 +517,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
520517
}
521518
if (defn.isSyntheticFunctionClass(sym))
522519
sigName(defn.erasedFunctionType(sym))
523-
else if (defn.isPhantomTerminalClass(tp.symbol))
524-
sigName(PhantomErasure.erasedPhantomType)
525520
else
526521
normalizeClass(sym.asClass).fullName.asTypeName
527522
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
@@ -129,7 +129,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
129129
// Produce aligned accessors and constructor parameters. We have to adjust
130130
// for any outer parameters, which are last in the sequence of original
131131
// parameter accessors but come first in the constructor parameter list.
132-
val accessors = cls.paramAccessors.filterNot(x => x.isSetter || x.info.resultType.classSymbol == defn.ErasedPhantomClass)
132+
val accessors = cls.paramAccessors.filterNot(x => x.isSetter)
133133
val vparamsWithOuterLast = vparams match {
134134
case vparam :: rest if vparam.name == nme.OUTER => rest ::: vparam :: Nil
135135
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 {
@@ -210,8 +209,6 @@ object Erasure {
210209
val tree1 =
211210
if (tree.tpe isRef defn.NullClass)
212211
adaptToType(tree, underlying)
213-
else if (wasPhantom(underlying))
214-
PhantomErasure.erasedParameterRef
215212
else if (!(tree.tpe <:< tycon)) {
216213
assert(!(tree.tpe.typeSymbol.isPrimitiveValueClass))
217214
val nullTree = Literal(Constant(null))
@@ -427,16 +424,9 @@ object Erasure {
427424
}
428425
}
429426

430-
if ((origSym eq defn.Phantom_assume) || (origSym.is(Flags.ParamAccessor) && wasPhantom(pt)))
431-
PhantomErasure.erasedAssume
432-
else recur(typed(tree.qualifier, AnySelectionProto))
427+
recur(typed(tree.qualifier, AnySelectionProto))
433428
}
434429

435-
override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): tpd.Tree =
436-
if (tree.symbol eq defn.Phantom_assume) PhantomErasure.erasedAssume
437-
else if (tree.symbol.is(Flags.Param) && wasPhantom(tree.typeOpt)) PhantomErasure.erasedParameterRef
438-
else super.typedIdent(tree, pt)
439-
440430
override def typedThis(tree: untpd.This)(implicit ctx: Context): Tree =
441431
if (tree.symbol == ctx.owner.lexicallyEnclosingClass || tree.symbol.isStaticOwner) promote(tree)
442432
else {
@@ -496,11 +486,9 @@ object Erasure {
496486
.withType(defn.ArrayOf(defn.ObjectType))
497487
args0 = bunchedArgs :: Nil
498488
}
499-
// Arguments are phantom if an only if the parameters are phantom, guaranteed by the separation of type lattices
500-
val args1 = args0.filterConserve(arg => !wasPhantom(arg.typeOpt))
501-
assert(args1 hasSameLengthAs mt.paramInfos)
502-
val args2 = args1.zipWithConserve(mt.paramInfos)(typedExpr)
503-
untpd.cpy.Apply(tree)(fun1, args2) withType mt.resultType
489+
assert(args0 hasSameLengthAs mt.paramInfos)
490+
val args1 = args0.zipWithConserve(mt.paramInfos)(typedExpr)
491+
untpd.cpy.Apply(tree)(fun1, args1) withType mt.resultType
504492
case _ =>
505493
throw new MatchError(i"tree $tree has unexpected type of function ${fun1.tpe.widen}, was ${fun.typeOpt.widen}")
506494
}
@@ -561,11 +549,6 @@ object Erasure {
561549
rhs1 = untpd.Block(paramDefs, rhs1)
562550
}
563551
vparamss1 = vparamss1.mapConserve(_.filterConserve(!_.symbol.is(Flags.Unused)))
564-
vparamss1 = vparamss1.mapConserve(_.filterConserve(vparam => !wasPhantom(vparam.tpe)))
565-
if (sym.is(Flags.ParamAccessor) && wasPhantom(ddef.tpt.tpe)) {
566-
sym.resetFlag(Flags.ParamAccessor)
567-
rhs1 = PhantomErasure.erasedParameterRef
568-
}
569552
val ddef1 = untpd.cpy.DefDef(ddef)(
570553
tparams = Nil,
571554
vparamss = vparamss1,
@@ -680,7 +663,4 @@ object Erasure {
680663

681664
def takesBridges(sym: Symbol)(implicit ctx: Context) =
682665
sym.isClass && !sym.is(Flags.Trait | Flags.Package)
683-
684-
private def wasPhantom(tp: Type)(implicit ctx: Context): Boolean =
685-
tp.widenDealias.classSymbol eq defn.ErasedPhantomClass
686666
}

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

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

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ object GenericSignatures {
240240

241241
case mtpe: MethodType =>
242242
// unused method parameters do not make it to the bytecode.
243-
val params = if (mtpe.isUnusedMethod) Nil else mtpe.paramInfos.filterNot(_.isPhantom)
243+
val params = if (mtpe.isUnusedMethod) Nil else mtpe.paramInfos
244244
val restpe = mtpe.resultType
245245
builder.append('(')
246246
// TODO: Update once we support varargs

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: 2 additions & 2 deletions
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 _)
@@ -191,7 +191,7 @@ class SyntheticMethods(thisPhase: DenotTransformer) {
191191
*/
192192
def valueHashCodeBody(implicit ctx: Context): Tree = {
193193
assert(accessors.nonEmpty)
194-
assert(accessors.tail.forall(a => a.info.isPhantom || a.is(Unused)))
194+
assert(accessors.tail.forall(_ is Unused))
195195
ref(accessors.head).select(nme.hashCode_).ensureApplied
196196
}
197197

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

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package dotty.tools.dotc.transform
22

33
import dotty.tools.dotc.ast.tpd
4+
import dotty.tools.dotc.ast.Trees._
45
import dotty.tools.dotc.core.Contexts._
56
import dotty.tools.dotc.core.Symbols._
67
import dotty.tools.dotc.core.Types._
8+
import dotty.tools.dotc.core.StdNames._
79
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
810
import dotty.tools.dotc.typer.EtaExpansion
911

@@ -36,9 +38,10 @@ class UnusedArgLift extends MiniPhase {
3638

3739
/** Check what the phase achieves, to be called at any point after it is finished. */
3840
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match {
39-
case tree: Apply =>
40-
tree.args.foreach { arg =>
41-
assert(!arg.tpe.isPhantom || isPureExpr(arg))
41+
case tree: Apply if tree.tpe.widen.isUnusedMethod =>
42+
tree.args.foreach {
43+
case TypeApply(Select(Literal(const), nme.asInstanceOf_),List(tpt: TypeTree)) if const.value == null && tpt.tpe.isPhantom => // OK
44+
case arg => assert(isPureExpr(arg), arg)
4245
}
4346
case _ =>
4447
}
@@ -47,29 +50,15 @@ class UnusedArgLift extends MiniPhase {
4750

4851
override def transformApply(tree: Apply)(implicit ctx: Context): Tree = tree.tpe.widen match {
4952
case _: MethodType => tree // Do the transformation higher in the tree if needed
50-
case _ =>
51-
if (!hasImpurePhantomArgs(tree) && !hasUnusedParams(tree)) tree
52-
else {
53-
val buffer = ListBuffer.empty[Tree]
54-
val app = EtaExpansion.liftApp(buffer, tree)
55-
seq(buffer.result(), app)
56-
}
53+
case _ if hasUnusedParams(tree) =>
54+
val buffer = ListBuffer.empty[Tree]
55+
val app = EtaExpansion.liftApp(buffer, tree)
56+
seq(buffer.result(), app)
57+
case _ => tree
5758
}
5859

5960
/* private methods */
6061

61-
/** Returns true if at least on of the arguments is an impure phantom.
62-
* Inner applies are also checked in case of multiple parameter list.
63-
*/
64-
private def hasImpurePhantomArgs(tree: Apply)(implicit ctx: Context): Boolean = {
65-
tree.args.exists(arg => arg.tpe.isPhantom && !isPureExpr(arg)) || {
66-
tree.fun match {
67-
case fun: Apply => hasImpurePhantomArgs(fun)
68-
case _ => false
69-
}
70-
}
71-
}
72-
7362
/** Returns true if at least on of the arguments is an unused parameter.
7463
* Inner applies are also checked in case of multiple parameter list.
7564
*/

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,16 @@ class UnusedChecks extends MiniPhase {
3838

3939
override def transformDefDef(tree: DefDef)(implicit ctx: Context): tree.type = {
4040
checkUnusedNothing(tree)
41+
checkPhantomIsUnused(tree)
4142
checkedValOrDefDefRHS(tree)
43+
4244
}
4345

4446
override def transformValDef(tree: ValDef)(implicit ctx: Context): tree.type = {
4547
checkUnusedNothing(tree)
4648
if (tree.symbol.is(Unused) && tree.symbol.is(MutableOrLazy))
4749
ctx.error(tree.symbol.showKind + " cannot be unused", tree.pos)
50+
checkPhantomIsUnused(tree)
4851
checkedValOrDefDefRHS(tree)
4952
}
5053

@@ -99,4 +102,11 @@ class UnusedChecks extends MiniPhase {
99102

100103
private def isUnusedContext(implicit ctx: Context): Boolean =
101104
ctx.owner.ownersIterator.exists(_.is(Unused)) // TODO make context mode?
105+
106+
private def checkPhantomIsUnused(tree: ValOrDefDef)(implicit ctx: Context): Unit = {
107+
if (!tree.symbol.is(Unused) && tree.tpt.tpe.finalResultType.isPhantom) {
108+
if (tree.symbol.is(Param)) ctx.error("phantom parameters must be `unused`", tree.pos)
109+
else ctx.error(tree.symbol.showKind + " must be `unused` to return a phantom", tree.pos)
110+
}
111+
}
102112
}

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: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -494,12 +494,10 @@ object Checking {
494494
case param :: params =>
495495
if (param.is(Mutable))
496496
ctx.error(ValueClassParameterMayNotBeAVar(clazz, param), param.pos)
497-
if (param.info.isPhantom)
498-
ctx.error("value class first parameter must not be phantom", param.pos)
499-
else if (param.is(Unused))
497+
if (param.is(Unused))
500498
ctx.error("value class first parameter cannot be `unused`", param.pos)
501499
else {
502-
for (p <- params if !(p.info.isPhantom || p.is(Unused)))
500+
for (p <- params if !p.is(Unused))
503501
ctx.error("value class can only have one non `unused` parameter", p.pos)
504502
}
505503
case Nil =>

0 commit comments

Comments
 (0)