diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 5c01c8ca59d1..e1d96af39e33 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -990,4 +990,10 @@ class Definitions { /** If the symbol is of the class scala.Phantom.Any or scala.Phantom.Nothing */ def isPhantomTerminalClass(sym: Symbol) = (sym eq Phantom_AnyClass) || (sym eq Phantom_NothingClass) + + lazy val ErasedPhantomType: TypeRef = ctx.requiredClassRef("dotty.runtime.ErasedPhantom") + def ErasedPhantomClass(implicit ctx: Context) = ErasedPhantomType.symbol.asClass + + def ErasedPhantom_UNIT(implicit ctx: Context) = ErasedPhantomClass.linkedClass.requiredValue("UNIT") + } diff --git a/compiler/src/dotty/tools/dotc/core/PhantomErasure.scala b/compiler/src/dotty/tools/dotc/core/PhantomErasure.scala index fbd10f004c49..9064bc5aaad9 100644 --- a/compiler/src/dotty/tools/dotc/core/PhantomErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/PhantomErasure.scala @@ -7,22 +7,18 @@ import dotty.tools.dotc.core.Types.Type /** Phantom erasure erases (minimal erasure): * - * - Parameters/arguments are erased to BoxedUnit. The next step will remove the parameters + * - Parameters/arguments are erased to ErasedPhantom. The next step will remove the parameters * from the method definitions and calls (implemented in branch implement-phantom-types-part-2). - * - Definitions of `def`, `val`, `lazy val` and `var` returning a phantom type to return a BoxedUnit. Where fields - * with BoxedUnit type are not memoized (see transform/Memoize.scala). - * - Calls to Phantom.assume become calls to BoxedUnit. Intended to be optimized away by local optimizations. - * - * BoxedUnit is used as it fits perfectly and homogeneously in all locations where phantoms can be found. - * Additionally some of the optimizations that can be performed on phantom types can also be directly implemented - * on all boxed units. + * - Definitions of `def`, `val`, `lazy val` and `var` returning a phantom type to return a ErasedPhantom. Where fields + * with ErasedPhantom type are not memoized (see transform/Memoize.scala). + * - Calls to Phantom.assume become calls to ErasedPhantom.UNIT. Intended to be optimized away by local optimizations. */ object PhantomErasure { /** Returns the default erased type of a phantom type */ - def erasedPhantomType(implicit ctx: Context): Type = defn.BoxedUnitType + def erasedPhantomType(implicit ctx: Context): Type = defn.ErasedPhantomType /** Returns the default erased tree for a call to Phantom.assume */ - def erasedAssume(implicit ctx: Context): Tree = ref(defn.BoxedUnit_UNIT) + def erasedAssume(implicit ctx: Context): Tree = ref(defn.ErasedPhantom_UNIT) } diff --git a/compiler/src/dotty/tools/dotc/transform/Memoize.scala b/compiler/src/dotty/tools/dotc/transform/Memoize.scala index 293bac40887b..a6bb93e4ecf4 100644 --- a/compiler/src/dotty/tools/dotc/transform/Memoize.scala +++ b/compiler/src/dotty/tools/dotc/transform/Memoize.scala @@ -99,17 +99,19 @@ import Decorators._ val NoFieldNeeded = Lazy | Deferred | JavaDefined | (if (ctx.settings.YnoInline.value) EmptyFlags else Inline) def isErasableBottomField(cls: Symbol): Boolean = { - // TODO: For Scala.js, return false if this field is in a js.Object unless it was a Phantom before erasure. - // Could time travel to detect phantom types or add an annotation before erasure. - !field.isVolatile && ((cls eq defn.NothingClass) || (cls eq defn.NullClass) || (cls eq defn.BoxedUnitClass)) + // TODO: For Scala.js, return false if this field is in a js.Object unless it is an ErasedPhantomClass. + !field.isVolatile && + ((cls eq defn.NothingClass) || (cls eq defn.NullClass) || (cls eq defn.BoxedUnitClass) || (cls eq defn.ErasedPhantomClass)) } def erasedBottomTree(sym: Symbol) = { if (sym eq defn.NothingClass) Throw(Literal(Constant(null))) else if (sym eq defn.NullClass) Literal(Constant(null)) + else if (sym eq defn.BoxedUnitClass) ref(defn.BoxedUnit_UNIT) + else if (sym eq defn.ErasedPhantomClass) ref(defn.ErasedPhantom_UNIT) else { - assert(sym eq defn.BoxedUnitClass) - ref(defn.BoxedUnit_UNIT) + assert(false, sym + " has no erased bottom tree") + EmptyTree } } diff --git a/library/src/dotty/runtime/ErasedPhantom.java b/library/src/dotty/runtime/ErasedPhantom.java new file mode 100644 index 000000000000..98fac71b4304 --- /dev/null +++ b/library/src/dotty/runtime/ErasedPhantom.java @@ -0,0 +1,30 @@ +package dotty.runtime; + + +/** Unit type representing an erased phantom value. + * + * Based on implementation of BoxedUnit. + */ +public final class ErasedPhantom implements java.io.Serializable { + private static final long serialVersionUID = 4116021023472525845L; + + public final static ErasedPhantom UNIT = new ErasedPhantom(); + + public final static Class TYPE = java.lang.Void.TYPE; + + private Object readResolve() { return UNIT; } + + private ErasedPhantom() { } + + public boolean equals(java.lang.Object other) { + return this == other; + } + + public int hashCode() { + return 0; + } + + public String toString() { + return "(\uD83D\uDC7B )"; + } +}