diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 34a4cec0d8fc..2594d95df66b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -670,16 +670,6 @@ object desugar { tree } - /** EmptyTree in lower bound ==> Nothing - * EmptyTree in upper bounds ==> Any - */ - def typeBoundsTree(tree: TypeBoundsTree)(implicit ctx: Context): TypeBoundsTree = { - val TypeBoundsTree(lo, hi) = tree - val lo1 = if (lo.isEmpty) untpd.TypeTree(defn.NothingType) else lo - val hi1 = if (hi.isEmpty) untpd.TypeTree(defn.AnyType) else hi - cpy.TypeBoundsTree(tree)(lo1, hi1) - } - /** Make closure corresponding to function. * params => body * ==> diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 0920ca946598..4bf2b36052de 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -820,7 +820,7 @@ class Definitions { lazy val UnqualifiedOwnerTypes: Set[NamedType] = RootImportTypes.toSet[NamedType] ++ RootImportTypes.map(_.symbol.moduleClass.typeRef) - lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass) + lazy val NotRuntimeClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass) /** Classes that are known not to have an initializer irrespective of * whether NoInits is set. Note: FunctionXXLClass is in this set @@ -832,7 +832,7 @@ class Definitions { * trait gets screwed up. Therefore, it is mandatory that FunctionXXL * is treated as a NoInit trait. */ - lazy val NoInitClasses = PhantomClasses + FunctionXXLClass + lazy val NoInitClasses = NotRuntimeClasses + FunctionXXLClass def isPolymorphicAfterErasure(sym: Symbol) = (sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf) @@ -936,7 +936,8 @@ class Definitions { NullClass, NothingClass, SingletonClass, - EqualsPatternClass) + EqualsPatternClass, + PhantomClass) lazy val syntheticCoreClasses = syntheticScalaClasses ++ List( EmptyPackageVal, @@ -963,4 +964,23 @@ class Definitions { _isInitialized = true } } + + // ----- Phantoms --------------------------------------------------------- + + lazy val PhantomClass: ClassSymbol = { + val cls = completeClass(enterCompleteClassSymbol(ScalaPackageClass, tpnme.Phantom, NoInitsTrait, List(AnyType))) + + val any = enterCompleteClassSymbol(cls, tpnme.Any, Protected | Final | NoInitsTrait, Nil) + val nothing = enterCompleteClassSymbol(cls, tpnme.Nothing, Protected | Final | NoInitsTrait, List(any.typeRef)) + enterMethod(cls, nme.assume_, MethodType(Nil, nothing.typeRef), Protected | Final | Method) + + cls + } + lazy val Phantom_AnyClass = PhantomClass.unforcedDecls.find(_.name eq tpnme.Any).asClass + lazy val Phantom_NothingClass = PhantomClass.unforcedDecls.find(_.name eq tpnme.Nothing).asClass + lazy val Phantom_assume = PhantomClass.unforcedDecls.find(_.name eq nme.assume_) + + /** 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) + } diff --git a/compiler/src/dotty/tools/dotc/core/PhantomErasure.scala b/compiler/src/dotty/tools/dotc/core/PhantomErasure.scala new file mode 100644 index 000000000000..b75d71cdf65a --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/PhantomErasure.scala @@ -0,0 +1,28 @@ +package dotty.tools.dotc.core + +import dotty.tools.dotc.ast.tpd._ +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.core.Symbols.defn +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 + * 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. The next step + * is to erase the fields for phantom types (implemented in branch implement-phantom-types-part-3) + * - 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. + */ +object PhantomErasure { + + /** Returns the default erased type of a phantom type */ + def erasedPhantomType(implicit ctx: Context): Type = defn.BoxedUnitType + + /** Returns the default erased tree for a call to Phantom.assume */ + def erasedAssume(implicit ctx: Context): Tree = ref(defn.BoxedUnit_UNIT) + +} diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index a7f658849dd8..60c6a6ed06c0 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -237,6 +237,8 @@ object StdNames { final val SourceFileATTR: N = "SourceFile" final val SyntheticATTR: N = "Synthetic" + final val Phantom: N = "Phantom" + // ----- Term names ----------------------------------------- // Compiler-internal diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index e01dab87228c..310838d8aa73 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -483,8 +483,8 @@ object SymDenotations { def isNumericValueClass(implicit ctx: Context) = maybeOwner == defn.ScalaPackageClass && defn.ScalaNumericValueClasses().contains(symbol) - /** Is symbol a phantom class for which no runtime representation exists? */ - def isPhantomClass(implicit ctx: Context) = defn.PhantomClasses contains symbol + /** Is symbol a class for which no runtime representation exists? */ + def isNotRuntimeClass(implicit ctx: Context) = defn.NotRuntimeClasses contains symbol /** Is this symbol a class representing a refinement? These classes * are used only temporarily in Typer and Unpickler as an intermediate @@ -635,7 +635,7 @@ object SymDenotations { /** Is this symbol a class references to which that are supertypes of null? */ final def isNullableClass(implicit ctx: Context): Boolean = - isClass && !isValueClass && !(this is ModuleClass) && symbol != defn.NothingClass + isClass && !isValueClass && !(this is ModuleClass) && symbol != defn.NothingClass && !defn.isPhantomTerminalClass(symbol) /** Is this definition accessible as a member of tree with type `pre`? * @param pre The type of the tree from which the selection is made diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 36c134a95d2f..0073257d96a4 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -47,6 +47,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { private var myAnyClass: ClassSymbol = null private var myNothingClass: ClassSymbol = null private var myNullClass: ClassSymbol = null + private var myPhantomNothingClass: ClassSymbol = null private var myObjectClass: ClassSymbol = null private var myAnyType: TypeRef = null private var myNothingType: TypeRef = null @@ -63,6 +64,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { if (myNullClass == null) myNullClass = defn.NullClass myNullClass } + def PhantomNothingClass = { + if (myPhantomNothingClass == null) myPhantomNothingClass = defn.Phantom_NothingClass + myPhantomNothingClass + } def ObjectClass = { if (myObjectClass == null) myObjectClass = defn.ObjectClass myObjectClass @@ -550,8 +555,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case OrType(tp1, tp2) => isNullable(tp1) || isNullable(tp2) case _ => false } - (tp1.symbol eq NothingClass) && tp2.isValueTypeOrLambda || - (tp1.symbol eq NullClass) && isNullable(tp2) + val sym1 = tp1.symbol + (sym1 eq NothingClass) && tp2.isValueTypeOrLambda && !tp2.isPhantom || + (sym1 eq NullClass) && isNullable(tp2) || + (sym1 eq PhantomNothingClass) && tp1.topType == tp2.topType } case tp1: SingletonType => /** if `tp2 == p.type` and `p: q.type` then try `tp1 <:< q.type` as a last effort.*/ diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index b8a7d2aeed97..5f3e1b5737bf 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -364,6 +364,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp) else if (sym == defn.ArrayClass) apply(tp.appliedTo(TypeBounds.empty)) // i966 shows that we can hit a raw Array type. else if (defn.isSyntheticFunctionClass(sym)) defn.erasedFunctionType(sym) + else if (defn.isPhantomTerminalClass(tp.symbol)) PhantomErasure.erasedPhantomType else eraseNormalClassRef(tp) case tp: RefinedType => val parent = tp.parent @@ -403,7 +404,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean case tr :: trs1 => assert(!tr.classSymbol.is(Trait), cls) val tr1 = if (cls is Trait) defn.ObjectType else tr - tr1 :: trs1.filterNot(_ isRef defn.ObjectClass) + // We remove the Phantom trait to erase the definitions of Phantom.{assume, Any, Nothing} + tr1 :: trs1.filterNot(x => x.isRef(defn.ObjectClass) || x.isRef(defn.PhantomClass)) case nil => nil } val erasedDecls = decls.filteredScope(sym => !sym.isType || sym.isClass) @@ -506,6 +508,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean } if (defn.isSyntheticFunctionClass(sym)) sigName(defn.erasedFunctionType(sym)) + else if (defn.isPhantomTerminalClass(tp.symbol)) + sigName(PhantomErasure.erasedPhantomType) else normalizeClass(sym.asClass).fullName.asTypeName case defn.ArrayOf(elem) => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 637239db038c..9a25da62be1c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -172,7 +172,44 @@ object Types { case _ => false } - cls == defn.AnyClass || loop(this) + loop(this) + } + + /** Returns true if the type is a phantom type + * - true if XYZ extends scala.Phantom and this type is upper bounded XYZ.Any + * - false otherwise + */ + final def isPhantom(implicit ctx: Context): Boolean = phantomLatticeType.exists + + /** Returns the top type of the lattice + * - XYX.Any if XYZ extends scala.Phantom and this type is upper bounded XYZ.Any + * - scala.Any otherwise + */ + final def topType(implicit ctx: Context): Type = { + val lattice = phantomLatticeType + if (lattice.exists) lattice.select(tpnme.Any) + else defn.AnyType + } + + /** Returns the bottom type of the lattice + * - XYZ.Nothing if XYZ extends scala.Phantom and this type is upper bounded XYZ.Any + * - scala.Nothing otherwise + */ + final def bottomType(implicit ctx: Context): Type = { + val lattice = phantomLatticeType + if (lattice.exists) lattice.select(tpnme.Nothing) + else defn.NothingType + } + + /** Returns the type of the phantom lattice (i.e. the prefix of the phantom type) + * - XYZ if XYZ extends scala.Phantom and this type is upper bounded XYZ.Any + * - NoType otherwise + */ + private final def phantomLatticeType(implicit ctx: Context): Type = widen match { + case tp: ClassInfo if defn.isPhantomTerminalClass(tp.classSymbol) => tp.prefix + case tp: TypeProxy if tp.superType ne this => tp.underlying.phantomLatticeType + case tp: AndOrType => tp.tp1.phantomLatticeType + case _ => NoType } /** Is this type guaranteed not to have `null` as a value? diff --git a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala index 683c8ac38a6c..9a768e464483 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -89,7 +89,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati case _ => val elemType = tree.tpe.elemType var elemClass = elemType.classSymbol - if (defn.PhantomClasses contains elemClass) elemClass = defn.ObjectClass + if (defn.NotRuntimeClasses contains elemClass) elemClass = defn.ObjectClass ref(defn.DottyArraysModule) .select(nme.seqToArray) .appliedToType(elemType) diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 1d761f32acb0..cc41ce00329e 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -28,6 +28,7 @@ import ValueClasses._ import TypeUtils._ import ExplicitOuter._ import core.Mode +import core.PhantomErasure class Erasure extends Phase with DenotTransformer { thisTransformer => @@ -454,6 +455,8 @@ object Erasure extends TypeTestsCasts{ val Apply(fun, args) = tree if (fun.symbol == defn.cbnArg) typedUnadapted(args.head, pt) + else if (fun.symbol eq defn.Phantom_assume) + PhantomErasure.erasedAssume else typedExpr(fun, FunProto(args, pt, this)) match { case fun1: Apply => // arguments passed in prototype were already passed fun1 diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index 546077d279a2..f90778df009a 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -174,7 +174,7 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => def superCallOpt(baseCls: Symbol): List[Tree] = superCalls.get(baseCls) match { case Some(call) => - if (defn.PhantomClasses.contains(baseCls)) Nil else call :: Nil + if (defn.NotRuntimeClasses.contains(baseCls)) Nil else call :: Nil case None => if (baseCls.is(NoInitsTrait) || defn.NoInitClasses.contains(baseCls)) Nil else { diff --git a/compiler/src/dotty/tools/dotc/transform/TreeGen.scala b/compiler/src/dotty/tools/dotc/transform/TreeGen.scala index 7e507d905894..a6dfdebc3cf4 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeGen.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeGen.scala @@ -14,7 +14,7 @@ object TreeGen { def wrapArrayMethodName(elemtp: Type)(implicit ctx: Context): TermName = { val elemCls = elemtp.classSymbol if (elemCls.isPrimitiveValueClass) nme.wrapXArray(elemCls.name) - else if (elemCls.derivesFrom(defn.ObjectClass) && !elemCls.isPhantomClass) nme.wrapRefArray + else if (elemCls.derivesFrom(defn.ObjectClass) && !elemCls.isNotRuntimeClass) nme.wrapRefArray else nme.genericWrapArray } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 4496c2bcf1c7..970b70be5679 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -418,7 +418,7 @@ trait TypeAssigner { tree.withType(avoidingType(expansion, bindings)) def assignType(tree: untpd.If, thenp: Tree, elsep: Tree)(implicit ctx: Context) = - tree.withType(thenp.tpe | elsep.tpe) + tree.withType(lubInSameUniverse(thenp :: elsep :: Nil, "branches of an if/else")) def assignType(tree: untpd.Closure, meth: Tree, target: Tree)(implicit ctx: Context) = tree.withType( @@ -428,15 +428,18 @@ trait TypeAssigner { def assignType(tree: untpd.CaseDef, body: Tree)(implicit ctx: Context) = tree.withType(body.tpe) - def assignType(tree: untpd.Match, cases: List[CaseDef])(implicit ctx: Context) = - tree.withType(ctx.typeComparer.lub(cases.tpes)) + def assignType(tree: untpd.Match, cases: List[CaseDef])(implicit ctx: Context) = { + if (tree.selector.typeOpt.isPhantom) + ctx.error("cannot pattern match on values of a phantom type", tree.selector.pos) + tree.withType(lubInSameUniverse(cases, "branches of a match")) + } def assignType(tree: untpd.Return)(implicit ctx: Context) = tree.withType(defn.NothingType) def assignType(tree: untpd.Try, expr: Tree, cases: List[CaseDef])(implicit ctx: Context) = if (cases.isEmpty) tree.withType(expr.tpe) - else tree.withType(ctx.typeComparer.lub(expr.tpe :: cases.tpes)) + else tree.withType(lubInSameUniverse(expr :: cases, "branches of a try")) def assignType(tree: untpd.SeqLiteral, elems: List[Tree], elemtpt: Tree)(implicit ctx: Context) = { val ownType = tree match { @@ -450,10 +453,10 @@ trait TypeAssigner { tree.withType(ref.tpe) def assignType(tree: untpd.AndTypeTree, left: Tree, right: Tree)(implicit ctx: Context) = - tree.withType(left.tpe & right.tpe) + tree.withType(inSameUniverse(_ & _, left.tpe, right, "an `&`")) def assignType(tree: untpd.OrTypeTree, left: Tree, right: Tree)(implicit ctx: Context) = - tree.withType(left.tpe | right.tpe) + tree.withType(inSameUniverse(_ | _, left.tpe, right, "an `|`")) /** Assign type of RefinedType. * Refinements are typed as if they were members of refinement class `refineCls`. @@ -484,7 +487,9 @@ trait TypeAssigner { tree.withType(ExprType(result.tpe)) def assignType(tree: untpd.TypeBoundsTree, lo: Tree, hi: Tree)(implicit ctx: Context) = - tree.withType(if (lo eq hi) TypeAlias(lo.tpe) else TypeBounds(lo.tpe, hi.tpe)) + tree.withType( + if (lo eq hi) TypeAlias(lo.tpe) + else inSameUniverse(TypeBounds(_, _), lo.tpe, hi, "type bounds")) def assignType(tree: untpd.Bind, sym: Symbol)(implicit ctx: Context) = tree.withType(NamedType.withFixedSym(NoPrefix, sym)) @@ -529,6 +534,24 @@ trait TypeAssigner { def assignType(tree: untpd.PackageDef, pid: Tree)(implicit ctx: Context) = tree.withType(pid.symbol.valRef) + + /** Ensure that `tree2`'s type is in the same universe as `tree1`. If that's the case, return + * `op` applied to both types. + * If not, issue an error and return `tree1`'s type. + */ + private def inSameUniverse(op: (Type, Type) => Type, tp1: Type, tree2: Tree, relationship: => String)(implicit ctx: Context): Type = + if (tp1.topType == tree2.tpe.topType) + op(tp1, tree2.tpe) + else { + ctx.error(ex"$tp1 and ${tree2.tpe} are in different universes. They cannot be combined in $relationship", tree2.pos) + tp1 + } + + private def lubInSameUniverse(trees: List[Tree], relationship: => String)(implicit ctx: Context): Type = + trees match { + case first :: rest => (first.tpe /: rest)(inSameUniverse(_ | _, _, _, relationship)) + case Nil => defn.NothingType + } } object TypeAssigner extends TypeAssigner diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ca9e0d126689..bc5d3c882bda 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1108,10 +1108,14 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } def typedTypeBoundsTree(tree: untpd.TypeBoundsTree)(implicit ctx: Context): TypeBoundsTree = track("typedTypeBoundsTree") { - val TypeBoundsTree(lo, hi) = desugar.typeBoundsTree(tree) + val TypeBoundsTree(lo, hi) = tree val lo1 = typed(lo) val hi1 = typed(hi) - val tree1 = assignType(cpy.TypeBoundsTree(tree)(lo1, hi1), lo1, hi1) + + val lo2 = if (lo1.isEmpty) typed(untpd.TypeTree(hi1.typeOpt.bottomType)) else lo1 + val hi2 = if (hi1.isEmpty) typed(untpd.TypeTree(lo1.typeOpt.topType)) else hi1 + + val tree1 = assignType(cpy.TypeBoundsTree(tree)(lo2, hi2), lo2, hi2) if (ctx.mode.is(Mode.Pattern)) { // Associate a pattern-bound type symbol with the wildcard. // The bounds of the type symbol can be constrained when comparing a pattern type @@ -1330,6 +1334,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit cls, isRequired, cdef.pos) } + // Check that phantom lattices are defined in a static object + if (cls.classParents.exists(_.classSymbol eq defn.PhantomClass) && !cls.isStaticOwner) + ctx.error("only static objects can extend scala.Phantom", cdef.pos) + // check value class constraints checkDerivedValueClass(cls, body1) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index c46d709a87ff..b701e9e1be24 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -152,6 +152,7 @@ class CompilationTests extends ParallelTesting { compileFile("../tests/neg/customArgs/noimports2.scala", defaultOptions.and("-Yno-imports")) + compileFile("../tests/neg/customArgs/overloadsOnAbstractTypes.scala", allowDoubleBindings) + compileFile("../tests/neg/customArgs/xfatalWarnings.scala", defaultOptions.and("-Xfatal-warnings")) + + compileFile("../tests/neg/customArgs/phantom-overload.scala", allowDoubleBindings) + compileFile("../tests/neg/tailcall/t1672b.scala", defaultOptions) + compileFile("../tests/neg/tailcall/t3275.scala", defaultOptions) + compileFile("../tests/neg/tailcall/t6574.scala", defaultOptions) + diff --git a/library/src/scala/Phantom.scala b/library/src/scala/Phantom.scala new file mode 100644 index 000000000000..4454a64cfe51 --- /dev/null +++ b/library/src/scala/Phantom.scala @@ -0,0 +1,12 @@ +/* Defined synthetically +package scala + +trait Phantom { + /** Phantom.Any does not extend scala.Any */ + protected /*final*/ trait Any + + protected final trait Nothing extends this.Any + + protected final def assume: this.Nothing +} +*/ diff --git a/tests/neg/customArgs/phantom-overload.scala b/tests/neg/customArgs/phantom-overload.scala new file mode 100644 index 000000000000..d4de97c7bbd3 --- /dev/null +++ b/tests/neg/customArgs/phantom-overload.scala @@ -0,0 +1,28 @@ + +class phantomOverload { + import Boo._ + import Boo2._ + + def foo1(): A = nothing + def foo1(): B = nothing // error + def foo1(): C = nothing2 // error + def foo1(): N = nothing // error + + def foo2(x: A) = ??? + def foo2(x: A) = ??? // error + def foo2(x: B) = ??? // error + def foo2(x: C) = ??? // error + def foo2(x: N) = ??? // error +} + +object Boo extends Phantom { + type A <: this.Any + type B <: this.Any + type N = this.Nothing + def nothing: this.Nothing = assume +} + +object Boo2 extends Phantom { + type C <: this.Any + def nothing2: this.Nothing = assume +} \ No newline at end of file diff --git a/tests/neg/phantom-AndOr.scala b/tests/neg/phantom-AndOr.scala new file mode 100644 index 000000000000..934bf037e51b --- /dev/null +++ b/tests/neg/phantom-AndOr.scala @@ -0,0 +1,18 @@ + +class BooFunDef1 { + import Boo._ + + def fun1(b: BooAny | Any) = ??? // error + def fun2(b: BooAny | Any | Any) = ??? // error // error + def fun3(b: Any | BooAny | Any) = ??? // error + def fun4(b: BooAny | BooAny | Any) = ??? // error + + def fun5(b: BooAny & Any) = ??? // error + def fun6(b: Any & BooAny & Any) = ??? // error + def fun7(b: BooAny & Any & Any) = ??? // error // error + def fun8(b: Any & Any & BooAny) = ??? // error +} + +object Boo extends Phantom { + type BooAny = this.Any +} diff --git a/tests/neg/phantom-Eq.scala b/tests/neg/phantom-Eq.scala new file mode 100644 index 000000000000..6d4fcb653260 --- /dev/null +++ b/tests/neg/phantom-Eq.scala @@ -0,0 +1,38 @@ +/* This is a example of how to implement Eq using erasable phantom types. + * + * See also: ../pos/phantomEq.scala + */ + +object PhantomEqTest { + import EqUtil._ + + "abc" === "abc" + 1 === 4 + + 1 === "abc" // error + "ghi" === 4 // error + 0 === Nil // error + List(1, 2) === 1 // error + List(1, 2) === "" // error + +} + +object EqUtil extends Phantom { + + type PhantomEq[-L, -R] <: this.Any + type PhantomEqEq[T] = PhantomEq[T, T] + + implicit class EqualsDeco[T](val x: T) extends AnyVal { + def ===[U] (y: U)(implicit ce: PhantomEq[T, U]) = x.equals(y) + } + + implicit def eqString: PhantomEqEq[String] = assume + implicit def eqInt: PhantomEqEq[Int] = assume + implicit def eqDouble: PhantomEqEq[Double] = assume + + implicit def eqByteNum: PhantomEq[Byte, Number] = assume + implicit def eqNumByte: PhantomEq[Number, Byte] = assume + + implicit def eqSeq[T, U](implicit eq: PhantomEq[T, U]): PhantomEq[Seq[T], Seq[U]] = assume + +} diff --git a/tests/neg/phantom-bottom.scala b/tests/neg/phantom-bottom.scala new file mode 100644 index 000000000000..7f6f2c2ff333 --- /dev/null +++ b/tests/neg/phantom-bottom.scala @@ -0,0 +1,25 @@ + +class BooFunDef1 { + import Boo._ + + def fun0(x: Foo): x.Y = Boo.nothing + + def fun1(x: Foo): x.Y = ??? // error + def fun2(x: Foo): x.Y = null // error + def fun3(x: Foo): x.Y = Boo2.nothing // error +} + +class Foo { + type Y <: Boo.BooAny +} + +object Boo extends Phantom { + type BooAny = this.Any + type BooNothing = this.Nothing + def nothing: BooNothing = assume +} + +object Boo2 extends Phantom { + type BooNothing2 = this.Nothing + def nothing: BooNothing2 = assume +} \ No newline at end of file diff --git a/tests/neg/phantom-classOf-1.scala b/tests/neg/phantom-classOf-1.scala new file mode 100644 index 000000000000..9e25d1b1a92f --- /dev/null +++ b/tests/neg/phantom-classOf-1.scala @@ -0,0 +1,10 @@ + +class phantomClassOf { + classOf[BooAny] // error + classOf[BooNothing] // error +} + +object Boo extends Phantom { + type BooAny = this.Any + type BooNothing = this.Nothing +} diff --git a/tests/neg/phantom-classOf-2.scala b/tests/neg/phantom-classOf-2.scala new file mode 100644 index 000000000000..1d3b0e3752f3 --- /dev/null +++ b/tests/neg/phantom-classOf-2.scala @@ -0,0 +1,10 @@ + +class phantomClassOf { + type Blinky <: Boo.BooAny + + classOf[Blinky] // error +} + +object Boo extends Phantom { + type BooAny = this.Any +} diff --git a/tests/neg/phantom-evidence.scala b/tests/neg/phantom-evidence.scala new file mode 100644 index 000000000000..1ba0477bc2d4 --- /dev/null +++ b/tests/neg/phantom-evidence.scala @@ -0,0 +1,37 @@ +/* This is a example of how to implement =:= using erasable phantom types. + * + * Run this test with + * `run tests/neg/phantomEvidence-1.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + * + * See also: ../pos/phantomEvidence-1.scala + */ + + +/** In this implementation variant of =:= (called =::=) we erase all instantiations and definitions of =::= */ +object WithNormalState extends Phantom { + + type =::=[From, To] <: this.Any + + implicit inline def tpEquals[A]: A =::= A = assume + + trait State + sealed trait On extends State + sealed trait Off extends State + + object Instance { + def newInstance(): Instance[Off] = new Instance[Off] + } + class Instance[S <: State] private { + def getOnInstance(implicit ev: S =::= Off): Instance[On] = new Instance[On] + def getOffInstance(implicit ev: S =::= On): Instance[Off] = new Instance[Off] + } + + def run() = { + val instance = Instance.newInstance() + instance.getOffInstance // error + instance.getOnInstance.getOnInstance // error + } + +} + diff --git a/tests/neg/phantom-expr.scala b/tests/neg/phantom-expr.scala new file mode 100644 index 000000000000..eff415121dae --- /dev/null +++ b/tests/neg/phantom-expr.scala @@ -0,0 +1,49 @@ + +class Foo { + import Boo._ + import Boo1._ + + type Blinky <: BooAny + type Inky <: BooAny + + val blinky = Boo.boo[Blinky] + val inky = Boo.boo[Inky] + + val b = true + def fooIf1 = + if (b) blinky + else "" // error + + def fooIf2 = + if (b) "" + else blinky // error + + def fooIf3 = + if (b) boo1 + else blinky // error + + def fooMatch1 = blinky match { // error + case _: Blinky => () + } + def fooMatch2 = 1 match { case 1 => 2 + case _ => blinky // error + } + def fooMatch3 = 1 match { + case 1 => boo1 + case _ => blinky // error + } + def fooTry = + try 1 + catch { case ex: Exception => blinky // error + } +} + +object Boo extends Phantom { + type BooAny = this.Any + def boo[B <: BooAny]: B = assume +} + +object Boo1 extends Phantom { + type Boo1Any = this.Any + def boo1: Boo1Any = assume +} diff --git a/tests/neg/phantom-fun-app.scala b/tests/neg/phantom-fun-app.scala new file mode 100644 index 000000000000..4e6e4424acec --- /dev/null +++ b/tests/neg/phantom-fun-app.scala @@ -0,0 +1,24 @@ + +class phantomFunApp { + import Boo._ // Note: this is dangerous as it imports Boo.Any as Any + + def foo1(a: Any) = ??? + def foo2(b: BooAny) = ??? + + foo1(1) + foo1(boo[Blinky]) // error + foo1(boo[Pinky]) // error + + foo2(boo[Blinky]) + foo2(boo[Pinky]) + foo2(1) // error + foo2("abc") // error + foo2(???) // error +} + +object Boo extends Phantom { + type BooAny = this.Any + type Blinky <: BooAny + type Pinky <: Blinky + def boo[B <: BooAny]: B = assume +} diff --git a/tests/neg/phantom-instanceOf-1.scala b/tests/neg/phantom-instanceOf-1.scala new file mode 100644 index 000000000000..7135c4281563 --- /dev/null +++ b/tests/neg/phantom-instanceOf-1.scala @@ -0,0 +1,11 @@ + +class phantomInstanceOf1 { + null.asInstanceOf[Boo.Any] // error + null.asInstanceOf[Boo.Nothing] // error + "".asInstanceOf[Boo.Any] // error + "".asInstanceOf[Boo.Nothing] // error +} + +object Boo extends Phantom { + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/neg/phantom-instanceOf-2.scala b/tests/neg/phantom-instanceOf-2.scala new file mode 100644 index 000000000000..c4164618623f --- /dev/null +++ b/tests/neg/phantom-instanceOf-2.scala @@ -0,0 +1,14 @@ + +class phantomInstanceOf2 { + import Boo._ + boo[Blinky].asInstanceOf[Any] // error + boo[Blinky].asInstanceOf[Nothing] // error + boo[Blinky].asInstanceOf[Blinky] // error + boo[Blinky].asInstanceOf[BooAny] // error +} + +object Boo extends Phantom { + type BooAny <: this.Any + type Blinky <: this.Any + def boo[B <: this.Any]: B = assume +} diff --git a/tests/neg/phantom-multiversal-AndOr.scala b/tests/neg/phantom-multiversal-AndOr.scala new file mode 100644 index 000000000000..9fc8ff8bc6df --- /dev/null +++ b/tests/neg/phantom-multiversal-AndOr.scala @@ -0,0 +1,21 @@ + +class BooFunDef1 { + import Universe1._ + import UniverseA._ + + def fun1(b: One | A) = ??? // error + def fun2(b: A | One) = ??? // error + def fun3(b: A | One | Any) = ??? // error // error + + def fun4(b: A & One) = ??? // error + def fun5(b: One & A) = ??? // error + def fun6(b: A & One & Any) = ??? // error // error +} + +object Universe1 extends Phantom { + type One <: this.Any +} + +object UniverseA extends Phantom { + type A <: this.Any +} diff --git a/tests/neg/phantom-multiversal-type-param-bounds-1.scala b/tests/neg/phantom-multiversal-type-param-bounds-1.scala new file mode 100644 index 000000000000..db3a5c1c3b63 --- /dev/null +++ b/tests/neg/phantom-multiversal-type-param-bounds-1.scala @@ -0,0 +1,18 @@ + +class phantomTypeParamBounds1 { + import Universe1._ + import UniverseA._ + + def fun1[X >: OneNothing <: AAny] = ??? // error + def fun2[X >: ANothing <: OneAny] = ??? // error +} + +object Universe1 extends Phantom { + type OneAny = this.Any + type OneNothing = this.Nothing +} + +object UniverseA extends Phantom { + type AAny = this.Any + type ANothing = this.Nothing +} diff --git a/tests/neg/phantom-multiversal-type-param-bounds-2.scala b/tests/neg/phantom-multiversal-type-param-bounds-2.scala new file mode 100644 index 000000000000..0e085578955b --- /dev/null +++ b/tests/neg/phantom-multiversal-type-param-bounds-2.scala @@ -0,0 +1,22 @@ + +class phantomTypeParamBounds2 { + import Universe1._ + import UniverseA._ + + def fun1[X <: One & A] = ??? // error + def fun2[X <: One | A] = ??? // error + def fun3[X >: OneNothing & ANothing] = ??? // error + def fun4[X >: OneNothing | ANothing] = ??? // error + + def fun5[X >: One & A <: One & A] = ??? // error // error +} + +object Universe1 extends Phantom { + type One <: this.Any + type OneNothing = this.Nothing +} + +object UniverseA extends Phantom { + type A <: this.Any + type ANothing = this.Nothing +} diff --git a/tests/neg/phantom-multiversal.scala b/tests/neg/phantom-multiversal.scala new file mode 100644 index 000000000000..af1571033e8f --- /dev/null +++ b/tests/neg/phantom-multiversal.scala @@ -0,0 +1,35 @@ + +class BooFunDef1 { + import Universe1._ + import UniverseA._ + + fun1(one, two) + fun1(one, b) // error + fun1(b, a) // error // error + + funA(a, b) + funA(a, one) // error + funA(two, one) // error // error + + funMulti(a, one, 42) + funMulti(a, b, 42) // error + funMulti(one, two, one) // error // error + + def fun1(x: One, y: Two) = ??? + def funA(k: A, l: B) = ??? + def funMulti(k: A, x: One, i: Int) = ??? +} + +object Universe1 extends Phantom { + type One = this.Any + type Two <: One + def one: One = assume + def two: Two = assume +} + +object UniverseA extends Phantom { + type A = this.Any + type B <: A + def a: A = assume + def b: B = assume +} diff --git a/tests/neg/phantom-trait-1.scala b/tests/neg/phantom-trait-1.scala new file mode 100644 index 000000000000..bdf2429d56eb --- /dev/null +++ b/tests/neg/phantom-trait-1.scala @@ -0,0 +1,4 @@ + +object Boo extends Phantom { + override val assume: this.Nothing = super.assume // error +} diff --git a/tests/neg/phantom-trait-2.scala b/tests/neg/phantom-trait-2.scala new file mode 100644 index 000000000000..d585db62a854 --- /dev/null +++ b/tests/neg/phantom-trait-2.scala @@ -0,0 +1,5 @@ + +object Boo1 extends Phantom { + class A extends this.Any // error + class B extends this.Nothing // error +} diff --git a/tests/neg/phantom-trait-3.scala b/tests/neg/phantom-trait-3.scala new file mode 100644 index 000000000000..1512e8e513b8 --- /dev/null +++ b/tests/neg/phantom-trait-3.scala @@ -0,0 +1,6 @@ + +class Boo1 extends Phantom // error + +trait Boo2 extends Phantom // error + +object Boo3 extends Phantom diff --git a/tests/neg/phantom-trait-4.scala b/tests/neg/phantom-trait-4.scala new file mode 100644 index 000000000000..19a7e7b670d1 --- /dev/null +++ b/tests/neg/phantom-trait-4.scala @@ -0,0 +1,23 @@ + +class Foo { + + object Boo1 extends Phantom // error + + def foo = { + object Boo2 extends Phantom // error + 42 + } +} + +object Foo { + object Boo1 extends Phantom + + def foo = { + object Boo2 extends Phantom // error + 42 + } +} + +package foo { + object Boo1 extends Phantom +} diff --git a/tests/neg/phantom-type-param-bounds-1.scala b/tests/neg/phantom-type-param-bounds-1.scala new file mode 100644 index 000000000000..5e2c7fe60579 --- /dev/null +++ b/tests/neg/phantom-type-param-bounds-1.scala @@ -0,0 +1,9 @@ + +class phantomTypeParamBounds1 { + def fun5[X >: Boo.Nothing <: Any] = ??? // error + def fun6[X >: Nothing <: Boo.Any] = ??? // error +} + +object Boo extends Phantom { + def boo[B <: this.Any]: B = assume +} diff --git a/tests/neg/phantom-type-param-bounds-2.scala b/tests/neg/phantom-type-param-bounds-2.scala new file mode 100644 index 000000000000..4f6d4ec06051 --- /dev/null +++ b/tests/neg/phantom-type-param-bounds-2.scala @@ -0,0 +1,13 @@ + +class phantomTypeParamBounds2 { + def fun1[X <: Boo.Any & Any] = ??? // error + def fun2[X <: Boo.Any | Any] = ??? // error + def fun3[X >: Boo.Nothing & Nothing] = ??? // error + def fun4[X >: Boo.Nothing | Nothing] = ??? // error + + def fun5[X >: Boo.Any & Any <: Boo.Any & Any] = ??? // error // error +} + +object Boo extends Phantom { + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/pos/phantom-Eq.scala b/tests/pos/phantom-Eq.scala new file mode 100644 index 000000000000..dcb8e213b912 --- /dev/null +++ b/tests/pos/phantom-Eq.scala @@ -0,0 +1,42 @@ + +/* This is a example of how to implement Eq using erasable phantom types. + * + * Run this test with + * `run tests/pos/phantomEq.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + * + * See also: ../neg/phantomEq.scala + */ + +object PhantomEq { + import EqUtil._ + + "ghi" === "jkl" + 3 === 4 + 2.0 === 3.1 + + List(1, 2) === Nil + List(1, 2) === Vector(1, 2) + + 1.toByte === (1: Number) + (1: Number) === 1.toByte +} + +object EqUtil extends Phantom { + + type PhantomEq[-L, -R] <: this.Any + type PhantomEqEq[T] = PhantomEq[T, T] + + implicit class EqualsDeco[T](val x: T) extends AnyVal { + def ===[U] (y: U)(implicit ce: PhantomEq[T, U]) = x.equals(y) + } + + implicit def eqString: PhantomEqEq[String] = assume + implicit def eqInt: PhantomEqEq[Int] = assume + implicit def eqDouble: PhantomEqEq[Double] = assume + + implicit def eqByteNum: PhantomEq[Byte, Number] = assume + implicit def eqNumByte: PhantomEq[Number, Byte] = assume + + implicit def eqSeq[T, U](implicit eq: PhantomEq[T, U]): PhantomEq[Seq[T], Seq[U]] = assume +} diff --git a/tests/pos/phantom-Eq2/Phantom-Eq_1.scala b/tests/pos/phantom-Eq2/Phantom-Eq_1.scala new file mode 100644 index 000000000000..3d03c64e63a1 --- /dev/null +++ b/tests/pos/phantom-Eq2/Phantom-Eq_1.scala @@ -0,0 +1,20 @@ + +/* This is a version of ../pos/phantomEq.scala that tests phantom with separate compilation */ +object EqUtil extends Phantom { + + type PhantomEq[-L, -R] <: this.Any + type PhantomEqEq[T] = PhantomEq[T, T] + + implicit class EqualsDeco[T](val x: T) extends AnyVal { + def ===[U] (y: U)(implicit ce: PhantomEq[T, U]) = x.equals(y) + } + + implicit def eqString: PhantomEqEq[String] = assume + implicit def eqInt: PhantomEqEq[Int] = assume + implicit def eqDouble: PhantomEqEq[Double] = assume + + implicit def eqByteNum: PhantomEq[Byte, Number] = assume + implicit def eqNumByte: PhantomEq[Number, Byte] = assume + + implicit def eqSeq[T, U](implicit eq: PhantomEq[T, U]): PhantomEq[Seq[T], Seq[U]] = assume +} diff --git a/tests/pos/phantom-Eq2/Phantom-Eq_2.scala b/tests/pos/phantom-Eq2/Phantom-Eq_2.scala new file mode 100644 index 000000000000..c3f3254f6144 --- /dev/null +++ b/tests/pos/phantom-Eq2/Phantom-Eq_2.scala @@ -0,0 +1,15 @@ + +/* This is a version of ../pos/phantom.scala that tests phantom clases with separate compilation */ +object PhantomEq { + import EqUtil._ + + "ghi" === "jkl" + 3 === 4 + 2.0 === 3.1 + + List(1, 2) === Nil + List(1, 2) === Vector(1, 2) + + 1.toByte === (1: Number) + (1: Number) === 1.toByte +} diff --git a/tests/pos/phantom-Evidence.scala b/tests/pos/phantom-Evidence.scala new file mode 100644 index 000000000000..0e096177a115 --- /dev/null +++ b/tests/pos/phantom-Evidence.scala @@ -0,0 +1,38 @@ + +/* This is a example of how to implement =:= using erasable phantom types. + * + * Run this test with + * `run tests/pos/phantomEvidence-1.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + * + * See also: ../neg/phantomEvidence-1.scala + */ + +/** In this implementation variant of =:= (called =::=) we erase all instantiations and definitions of =::= */ +object WithNormalState { + import Utils._ + + trait State + sealed trait On extends State + sealed trait Off extends State + + object Instance { + def newInstance(): Instance[Off] = new Instance[Off] + } + class Instance[S <: State] private { + def getOnInstance(implicit ev: S =::= Off): Instance[On] = new Instance[On] // phantom parameter ev is erased + def getOffInstance(implicit ev: S =::= On): Instance[Off] = new Instance[Off] // phantom parameter ev is erased + } + + def run() = { + val instance = Instance.newInstance() + instance.getOnInstance // inferred phantom evidence parameter =::= is erased + instance.getOnInstance.getOffInstance.getOnInstance.getOffInstance // all inferred phantom evidence parameters =::= are erased + } + +} + +object Utils extends Phantom { + type =::=[From, To] <: this.Any + implicit def tpEquals[A]: A =::= A = assume +} diff --git a/tests/run/phantom-1.check b/tests/run/phantom-1.check new file mode 100644 index 000000000000..3e2c972a8273 --- /dev/null +++ b/tests/run/phantom-1.check @@ -0,0 +1 @@ +fun1 diff --git a/tests/run/phantom-1.scala b/tests/run/phantom-1.scala new file mode 100644 index 000000000000..38cdfaaf2236 --- /dev/null +++ b/tests/run/phantom-1.scala @@ -0,0 +1,22 @@ + +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun1(Boo.any) + } + + def fun1(boo: BooAny): Unit = { + println("fun1") + } +} + +object Boo extends Phantom { + type BooAny = this.Any + def any: BooAny = assume +} diff --git a/tests/run/phantom-2.check b/tests/run/phantom-2.check new file mode 100644 index 000000000000..2d4b6fc3b43a --- /dev/null +++ b/tests/run/phantom-2.check @@ -0,0 +1 @@ +fun2 diff --git a/tests/run/phantom-2.scala b/tests/run/phantom-2.scala new file mode 100644 index 000000000000..7d954dfa6b36 --- /dev/null +++ b/tests/run/phantom-2.scala @@ -0,0 +1,20 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun2(Boo.nothig) + } + + def fun2(bottom: BooNothing): Unit = { + println("fun2") + } +} + +object Boo extends Phantom { + type BooNothing = this.Nothing + def nothig: BooNothing = assume +} diff --git a/tests/run/phantom-3.check b/tests/run/phantom-3.check new file mode 100644 index 000000000000..86802c8797d5 --- /dev/null +++ b/tests/run/phantom-3.check @@ -0,0 +1,3 @@ +fun3 +fun3 +fun3 diff --git a/tests/run/phantom-3.scala b/tests/run/phantom-3.scala new file mode 100644 index 000000000000..45be3122f3b3 --- /dev/null +++ b/tests/run/phantom-3.scala @@ -0,0 +1,26 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun3(boo[Blinky], boo[Pinky]) + fun3(boo[Inky], boo[Pinky]) + fun3(boo[Pinky], boo[Casper]) + } + + def fun3(x1: Blinky, x2: Inky): Unit = { + println("fun3") + } +} + +object Boo extends Phantom { + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + type Casper = Pinky + def boo[B <: Blinky]: B = assume +} diff --git a/tests/run/phantom-4.check b/tests/run/phantom-4.check new file mode 100644 index 000000000000..9e4c79efcee0 --- /dev/null +++ b/tests/run/phantom-4.check @@ -0,0 +1,3 @@ +fun4 +fun4 +fun4 diff --git a/tests/run/phantom-4.scala b/tests/run/phantom-4.scala new file mode 100644 index 000000000000..1c1d58262068 --- /dev/null +++ b/tests/run/phantom-4.scala @@ -0,0 +1,27 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun4(3, 4, boo[Blinky], boo[Pinky]) + fun4(5, 6, boo[Inky], boo[Pinky]) + fun4(7, 8, boo[Pinky], boo[Casper]) + } + + def fun4(n: Int, n2: Int, top: Blinky, bottom: Pinky): Unit = { + println("fun4") + } + +} + +object Boo extends Phantom { + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + type Casper = Pinky + def boo[B <: Blinky]: B = assume +} diff --git a/tests/run/phantom-5.check b/tests/run/phantom-5.check new file mode 100644 index 000000000000..019a46ac7c15 --- /dev/null +++ b/tests/run/phantom-5.check @@ -0,0 +1,3 @@ +fun5 +fun5 +fun5 diff --git a/tests/run/phantom-5.scala b/tests/run/phantom-5.scala new file mode 100644 index 000000000000..8be113d8e2c0 --- /dev/null +++ b/tests/run/phantom-5.scala @@ -0,0 +1,27 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun5(boo[Blinky])(15)(boo[Pinky])(16) + fun5(boo[Inky])(17)(boo[Pinky])(18) + fun5(boo[Pinky])(19)(boo[Casper])(20) + } + + def fun5(top: Blinky)(n: Int)(bottom: Clyde)(n2: Int): Unit = { + println("fun5") + } +} + +object Boo extends Phantom { + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + type Clyde >: Pinky <: Inky + type Casper = Pinky + def boo[B <: Blinky]: B = assume +} diff --git a/tests/run/phantom-ImplicitFunctions-0.check b/tests/run/phantom-ImplicitFunctions-0.check new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/run/phantom-OnHList.check b/tests/run/phantom-OnHList.check new file mode 100644 index 000000000000..77a9e85ab6f2 --- /dev/null +++ b/tests/run/phantom-OnHList.check @@ -0,0 +1,4 @@ +() +(s,) +(1.0, 2.0, 3.0) +(s, 1.0, 2.0, 3.0) \ No newline at end of file diff --git a/tests/run/phantom-OnHList.scala b/tests/run/phantom-OnHList.scala new file mode 100644 index 000000000000..ee5da40619da --- /dev/null +++ b/tests/run/phantom-OnHList.scala @@ -0,0 +1,100 @@ + +/* Run this test with + * `run tests/run/phantomOnHList.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + * + * Disclaimer: This is only a prototype of HList that uses phantom evidences for the append operation + */ +object Test { + + + def main(args: Array[String]): Unit = { + println(HNil) + + val l1: String :: HNil = HList1("s") + println(l1) + + val l3: Double :: Double :: Double :: HNil = HList3(1d, 2d, 3d) + println(l3) + + val l4: String :: Double :: Double :: Double :: HNil = HListN[String, Double :: Double :: Double :: HNil](Array("s", 1d, 2d, 3d)) + println(l4) + } + +} + +// HList types ------------------------------------------------------------------------------------ + +sealed trait HList { def underlying: Array[Any] } +sealed trait ::[H, T <: HList] extends HList // Should be [+H, +T <: HList], see #1500 +sealed trait HNil extends HList + +// HList values ----------------------------------------------------------------------------------- + +final case object HNil extends HNil { + val underlying: Array[Any] = Array.empty[Any] + override def toString(): String = "()" +} + +// Case class based HLists for small sizes -------------------------------------------------------- + +final case class HList1[T1](e1: T1) extends (T1 :: HNil) { + def underlying: Array[Any] = Array(e1) + override def toString(): String = s"($e1,)" +} + +final case class HList2[T1, T2](e1: T1, e2: T2) extends (T1 :: T2 :: HNil) { + def underlying: Array[Any] = Array(e1, e2) + override def toString(): String = s"($e1, $e2)" +} + +final case class HList3[T1, T2, T3](e1: T1, e2: T2, e3: T3) extends (T1 :: T2 :: T3 :: HNil) { + def underlying: Array[Any] = Array(e1, e2, e3) + override def toString(): String = s"($e1, $e2, $e3)" +} + +// Array based HLists for large sizes ------------------------------------------------------------- + +final case class HListN[H, T <: HList](underlying: Array[Any]) extends (H :: T) { + override def toString() = underlying.mkString("(", ", ", ")") + + override def equals(o: Any): Boolean = + o match { + case l: HListN[_, _] => l.underlying.sameElements(underlying) + case _ => false + } + + override def hashCode: Int = { + var r = 1 + for (e <- underlying) + r = 31 * r + e.## + r + } +} + +object HListUnapply { + def unapplySeq[L <: HList](l: L): Option[Seq[Any]] = Some(l.underlying) +} + +// Low level (Array based) HLists Appender -------------------------------------------------------- + +trait Appender[L1 <: HList, L2 <: HList] { + type Out <: HList + def apply(l1: L1, l2: L2): Out +} + +object Appender { + implicit def lowLevelAppender[L1 <: HList, L2 <: HList, O <: HList](implicit p: PhantomAppender.Aux[L1, L2, O]): Appender[L1, L2] { type Out = O } = + new Appender[L1, L2] { + type Out = O + def apply(l1: L1, l2: L2): Out = HListN(Array.concat(l1.underlying, l2.underlying)).asInstanceOf[O] + } +} + +// Type level "only" computation of type Out ------------------------------------------------------ + +object PhantomAppender extends Phantom { + type Aux[L1 <: HList, L2 <: HList, O <: HList] <: this.Any + implicit def caseHNil[L <: HList]: Aux[HNil, L, L] = assume + implicit def caseHCons[H, T <: HList, L <: HList, O <: HList](implicit p: Aux[T, L, O]): Aux[H :: T, L, H :: O] = assume +} diff --git a/tests/run/phantom-decls-1.check b/tests/run/phantom-decls-1.check new file mode 100644 index 000000000000..b50ae590ec5c --- /dev/null +++ b/tests/run/phantom-decls-1.check @@ -0,0 +1,4 @@ +Boo1 +Boo1.polyfun1 +Boo1 +Boo1.polyfun1 diff --git a/tests/run/phantom-decls-1.scala b/tests/run/phantom-decls-1.scala new file mode 100644 index 000000000000..c2781abf1696 --- /dev/null +++ b/tests/run/phantom-decls-1.scala @@ -0,0 +1,29 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + new Boo1[BooAny]().polyfun1(boo[Blinky]) + new Boo1[BooAny]().polyfun1(boo[Inky]) + } + + def fun(top: BooAny): Unit = () + + class Boo1[P <: BooAny] { + println("Boo1") + def polyfun1(p1: P): Unit = { + println("Boo1.polyfun1") + } + } +} + +object Boo extends Phantom { + type BooAny = this.Any + type Blinky <: this.Any + type Inky <: Blinky + def boo[B <: Blinky]: B = assume +} diff --git a/tests/run/phantom-decls-2.check b/tests/run/phantom-decls-2.check new file mode 100644 index 000000000000..12166f8878fb --- /dev/null +++ b/tests/run/phantom-decls-2.check @@ -0,0 +1,6 @@ +Boo2 +Boo2.polyfun1 +Boo2 +Boo2.polyfun1 +Boo2 +Boo2.polyfun1 diff --git a/tests/run/phantom-decls-2.scala b/tests/run/phantom-decls-2.scala new file mode 100644 index 000000000000..4a4f594fe5f3 --- /dev/null +++ b/tests/run/phantom-decls-2.scala @@ -0,0 +1,31 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + new Boo2().polyfun1(boo[Blinky]) + new Boo2().polyfun1(boo[Inky]) + new Boo2().polyfun1(boo[Pinky]) + } + + class Boo2 { + println("Boo2") + type Boo3 = BooAny + def polyfun1(p2: Boo3): Unit = { + println("Boo2.polyfun1") + } + } +} + +object Boo extends Phantom { + type BooAny = this.Any + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + type Casper = Pinky + def boo[B <: this.Any]: B = assume +} diff --git a/tests/run/phantom-decls-3.check b/tests/run/phantom-decls-3.check new file mode 100644 index 000000000000..0e209e00a5bd --- /dev/null +++ b/tests/run/phantom-decls-3.check @@ -0,0 +1,4 @@ +Boo3 +Boo3.polyfun1 +Boo3 +Boo3.polyfun1 diff --git a/tests/run/phantom-decls-3.scala b/tests/run/phantom-decls-3.scala new file mode 100644 index 000000000000..fe18c8651f04 --- /dev/null +++ b/tests/run/phantom-decls-3.scala @@ -0,0 +1,36 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + + new Boo3(){ + type Boo1 = BooAny + }.polyfun1(boo[Pinky]) + + new Boo3(){ + type Boo1 = Blinky + }.polyfun1(boo[Blinky]) + + } + + trait Boo3 { + println("Boo3") + type Boo1 <: BooAny + def polyfun1(p3: Boo1): Unit = { + println("Boo3.polyfun1") + } + } +} + +object Boo extends Phantom { + type BooAny = this.Any + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: BooAny]: B = assume +} diff --git a/tests/run/phantom-decls-4.check b/tests/run/phantom-decls-4.check new file mode 100644 index 000000000000..ab02977bcee4 --- /dev/null +++ b/tests/run/phantom-decls-4.check @@ -0,0 +1,3 @@ +Boo4 +Boo4 +Boo4 diff --git a/tests/run/phantom-decls-4.scala b/tests/run/phantom-decls-4.scala new file mode 100644 index 000000000000..fe9d9251a329 --- /dev/null +++ b/tests/run/phantom-decls-4.scala @@ -0,0 +1,25 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + new Boo4(boo[Blinky]) + new Boo4(boo[Inky]) + new Boo4(boo[Pinky]) + } + + class Boo4(p4: Blinky) { + println("Boo4") + } +} + +object Boo extends Phantom { + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: Blinky]: B = assume +} diff --git a/tests/run/phantom-decls-5.check b/tests/run/phantom-decls-5.check new file mode 100644 index 000000000000..2a678b77b83a --- /dev/null +++ b/tests/run/phantom-decls-5.check @@ -0,0 +1,2 @@ +Boo5 +Boo5 diff --git a/tests/run/phantom-decls-5.scala b/tests/run/phantom-decls-5.scala new file mode 100644 index 000000000000..f5bb1a8ef711 --- /dev/null +++ b/tests/run/phantom-decls-5.scala @@ -0,0 +1,24 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + new Boo5[Blinky](boo[Pinky]) + new Boo5[Pinky](boo[Pinky]) + } + + class Boo5[P <: Blinky](p5: P) { + println("Boo5") + } +} + +object Boo extends Phantom { + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: Blinky]: B = assume +} diff --git a/tests/run/phantom-hk-1.check b/tests/run/phantom-hk-1.check new file mode 100644 index 000000000000..79a820550a35 --- /dev/null +++ b/tests/run/phantom-hk-1.check @@ -0,0 +1,3 @@ +hkFun1 +hkFun1 +hkFun1 diff --git a/tests/run/phantom-hk-1.scala b/tests/run/phantom-hk-1.scala new file mode 100644 index 000000000000..0e6692f5b730 --- /dev/null +++ b/tests/run/phantom-hk-1.scala @@ -0,0 +1,31 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + hkFun1(boo[Blinky]) + hkFun1(boo[Inky]) + hkFun1(boo[Pinky]) + } + + type HKPhantom[X <: Blinky] = X + + def hkFun1[Y <: Blinky](p9: HKPhantom[Y]) = { + println("hkFun1") + } + +} + +trait Phantoms { +} + +object Boo extends Phantom { + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: this.Any]: B = assume +} diff --git a/tests/run/phantom-hk-2.check b/tests/run/phantom-hk-2.check new file mode 100644 index 000000000000..a36ae238b71d --- /dev/null +++ b/tests/run/phantom-hk-2.check @@ -0,0 +1,3 @@ +hk2 +hk2 +hk2 diff --git a/tests/run/phantom-hk-2.scala b/tests/run/phantom-hk-2.scala new file mode 100644 index 000000000000..01fdaa893c62 --- /dev/null +++ b/tests/run/phantom-hk-2.scala @@ -0,0 +1,29 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + type HKPhantom[X <: BooAny] = X + + def main(args: Array[String]): Unit = { + fun(hkFun2(boo[Blinky])) + fun(hkFun2(boo[Inky])) + fun(hkFun2(boo[Pinky])) + } + + def fun(top: BooAny): Unit = println("hk2") + + def hkFun2[Y <: BooAny](p10: HKPhantom[Y]): HKPhantom[Y] = p10 +} + + +object Boo extends Phantom { + type BooAny = Boo.Any + type Blinky <: Boo.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/run/phantom-lazy-val.check b/tests/run/phantom-lazy-val.check new file mode 100644 index 000000000000..069e33cfba04 --- /dev/null +++ b/tests/run/phantom-lazy-val.check @@ -0,0 +1,3 @@ +1 +foo +2 diff --git a/tests/run/phantom-lazy-val.scala b/tests/run/phantom-lazy-val.scala new file mode 100644 index 000000000000..4764d1d5cbe7 --- /dev/null +++ b/tests/run/phantom-lazy-val.scala @@ -0,0 +1,27 @@ + +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + println(1) + foo + println(2) + foo + } + + lazy val foo = { + println("foo") + any + } + +} + +object Boo extends Phantom { + type BooAny = this.Any + def any: BooAny = assume +} diff --git a/tests/run/phantom-methods-1.check b/tests/run/phantom-methods-1.check new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/run/phantom-methods-1.scala b/tests/run/phantom-methods-1.scala new file mode 100644 index 000000000000..e823675cff07 --- /dev/null +++ b/tests/run/phantom-methods-1.scala @@ -0,0 +1,22 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun(phantomFun1()) + } + + def fun(top: BooAny): Unit = () + + def phantomFun1(): Pinky = boo[Pinky] +} + +object Boo extends Phantom { + type BooAny = Boo.Any + type Pinky <: Boo.Any + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/run/phantom-methods-10.check b/tests/run/phantom-methods-10.check new file mode 100644 index 000000000000..50cb66f41e35 --- /dev/null +++ b/tests/run/phantom-methods-10.check @@ -0,0 +1,3 @@ +fun +inky +pacFun4 diff --git a/tests/run/phantom-methods-10.scala b/tests/run/phantom-methods-10.scala new file mode 100644 index 000000000000..de2ea0685ffa --- /dev/null +++ b/tests/run/phantom-methods-10.scala @@ -0,0 +1,31 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomRefErasure,phantomErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun2.pacFun4(inky) + } + + def pacFun4(clyde: Inky) = { + println("pacFun4") + } + + def inky: Inky = { + println("inky") + boo[Inky] + } + + def fun2 = { + println("fun") + this + } +} + +object Boo extends Phantom { + type Inky <: this.Any + def boo[B <: this.Any]: B = assume +} diff --git a/tests/run/phantom-methods-2.check b/tests/run/phantom-methods-2.check new file mode 100644 index 000000000000..1e48428f80bc --- /dev/null +++ b/tests/run/phantom-methods-2.check @@ -0,0 +1,3 @@ +fun +fun +fun diff --git a/tests/run/phantom-methods-2.scala b/tests/run/phantom-methods-2.scala new file mode 100644 index 000000000000..e85784f31ca7 --- /dev/null +++ b/tests/run/phantom-methods-2.scala @@ -0,0 +1,26 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun(phantomFun2(Boo.boo[Blinky])) + fun(phantomFun2(Boo.boo[Inky])) + fun(phantomFun2(Boo.boo[Pinky])) + } + + def fun(top: Blinky): Unit = println("fun") + + def phantomFun2(p6: Blinky): Blinky = p6 + +} + +object Boo extends Phantom { + type Blinky <: Boo.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/run/phantom-methods-3.check b/tests/run/phantom-methods-3.check new file mode 100644 index 000000000000..1e48428f80bc --- /dev/null +++ b/tests/run/phantom-methods-3.check @@ -0,0 +1,3 @@ +fun +fun +fun diff --git a/tests/run/phantom-methods-3.scala b/tests/run/phantom-methods-3.scala new file mode 100644 index 000000000000..769c7c88f22e --- /dev/null +++ b/tests/run/phantom-methods-3.scala @@ -0,0 +1,26 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun(phantomFun3(boo[Blinky])) + fun(phantomFun3(boo[Inky])) + fun(phantomFun3(boo[Pinky])) + } + + def fun(top: Blinky): Unit = println("fun") + + def phantomFun3[P <: Blinky](p7: P): Blinky = p7 + +} + +object Boo extends Phantom { + type Blinky <: Boo.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/run/phantom-methods-4.check b/tests/run/phantom-methods-4.check new file mode 100644 index 000000000000..1e48428f80bc --- /dev/null +++ b/tests/run/phantom-methods-4.check @@ -0,0 +1,3 @@ +fun +fun +fun diff --git a/tests/run/phantom-methods-4.scala b/tests/run/phantom-methods-4.scala new file mode 100644 index 000000000000..070629037d54 --- /dev/null +++ b/tests/run/phantom-methods-4.scala @@ -0,0 +1,26 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun(phantomFun4(boo[Blinky])) + fun(phantomFun4(boo[Inky])) + fun(phantomFun4(boo[Blinky])) + } + + def fun(top: Blinky): Unit = println("fun") + + def phantomFun4[G <: Blinky](p8: G): G = p8 + +} + +object Boo extends Phantom { + type Blinky <: Boo.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/run/phantom-methods-5.check b/tests/run/phantom-methods-5.check new file mode 100644 index 000000000000..4e29067a1ff3 --- /dev/null +++ b/tests/run/phantom-methods-5.check @@ -0,0 +1,3 @@ +customFun1 +customFun1 +customFun1 diff --git a/tests/run/phantom-methods-5.scala b/tests/run/phantom-methods-5.scala new file mode 100644 index 000000000000..5a59c9ef7e94 --- /dev/null +++ b/tests/run/phantom-methods-5.scala @@ -0,0 +1,26 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + pacFun1(boo[Blinky]) + pacFun1(boo[Inky]) + pacFun1(boo[Pinky]) + } + + def pacFun1(blinky: Blinky) = { + println("customFun1") + } + +} + +object Boo extends Phantom { + type Blinky <: Boo.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/run/phantom-methods-6.check b/tests/run/phantom-methods-6.check new file mode 100644 index 000000000000..477c5c7817c8 --- /dev/null +++ b/tests/run/phantom-methods-6.check @@ -0,0 +1 @@ +customPhantomsFun2 diff --git a/tests/run/phantom-methods-6.scala b/tests/run/phantom-methods-6.scala new file mode 100644 index 000000000000..a994abc5b8f1 --- /dev/null +++ b/tests/run/phantom-methods-6.scala @@ -0,0 +1,24 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + pacFun2(boo[Pinky]) + } + + def pacFun2(pinky: Pinky) = { + println("customPhantomsFun2") + } + +} + +object Boo extends Phantom { + type Blinky <: Boo.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/run/phantom-methods-7.check b/tests/run/phantom-methods-7.check new file mode 100644 index 000000000000..002faad12556 --- /dev/null +++ b/tests/run/phantom-methods-7.check @@ -0,0 +1,2 @@ +pacFun3 +pacFun3 diff --git a/tests/run/phantom-methods-7.scala b/tests/run/phantom-methods-7.scala new file mode 100644 index 000000000000..afdc7b8c7aa2 --- /dev/null +++ b/tests/run/phantom-methods-7.scala @@ -0,0 +1,24 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + pacFun3(boo[Clyde]) + pacFun3(boo[Pinky]) + } + + def pacFun3(clyde: Clyde) = { + println("pacFun3") + } +} + +object Boo extends Phantom { + type Inky <: Boo.Any + type Pinky <: Inky + type Clyde >: Pinky <: Inky + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/run/phantom-methods-8.check b/tests/run/phantom-methods-8.check new file mode 100644 index 000000000000..1046cb49e89d --- /dev/null +++ b/tests/run/phantom-methods-8.check @@ -0,0 +1,2 @@ +inky +pacFun4 diff --git a/tests/run/phantom-methods-8.scala b/tests/run/phantom-methods-8.scala new file mode 100644 index 000000000000..c0bf096538aa --- /dev/null +++ b/tests/run/phantom-methods-8.scala @@ -0,0 +1,26 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomRefErasure,phantomErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + pacFun4(inky) + } + + def pacFun4(clyde: Inky) = { + println("pacFun4") + } + + def inky: Inky = { + println("inky") + Boo.boo[Inky] + } +} + +object Boo extends Phantom { + type Inky <: Boo.Any + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/run/phantom-methods-9.check b/tests/run/phantom-methods-9.check new file mode 100644 index 000000000000..50cb66f41e35 --- /dev/null +++ b/tests/run/phantom-methods-9.check @@ -0,0 +1,3 @@ +fun +inky +pacFun4 diff --git a/tests/run/phantom-methods-9.scala b/tests/run/phantom-methods-9.scala new file mode 100644 index 000000000000..4feb7bfcc730 --- /dev/null +++ b/tests/run/phantom-methods-9.scala @@ -0,0 +1,31 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomRefErasure,phantomErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + fun1().pacFun4(inky) + } + + def pacFun4(clyde: Inky) = { + println("pacFun4") + } + + def inky: Inky = { + println("inky") + boo[Inky] + } + + def fun1() = { + println("fun") + this + } +} + +object Boo extends Phantom { + type Inky <: Boo.Any + def boo[B <: Boo.Any]: B = assume +} diff --git a/tests/run/phantom-poly-1.check b/tests/run/phantom-poly-1.check new file mode 100644 index 000000000000..e2ee46abe5fe --- /dev/null +++ b/tests/run/phantom-poly-1.check @@ -0,0 +1,2 @@ +polyfun1 +polyfun1 diff --git a/tests/run/phantom-poly-1.scala b/tests/run/phantom-poly-1.scala new file mode 100644 index 000000000000..4f16c5dcb325 --- /dev/null +++ b/tests/run/phantom-poly-1.scala @@ -0,0 +1,23 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + polyfun1() + polyfun1[Casper]() + } + + def polyfun1[P <: Casper](): Unit = { + println("polyfun1") + } + +} + +object Boo extends Phantom { + type Casper <: this.Any + def boo[B <: this.Any]: B = assume +} diff --git a/tests/run/phantom-poly-2.check b/tests/run/phantom-poly-2.check new file mode 100644 index 000000000000..91de48245c31 --- /dev/null +++ b/tests/run/phantom-poly-2.check @@ -0,0 +1,3 @@ +polyfun2 +polyfun2 +polyfun2 diff --git a/tests/run/phantom-poly-2.scala b/tests/run/phantom-poly-2.scala new file mode 100644 index 000000000000..02152bf0ea4d --- /dev/null +++ b/tests/run/phantom-poly-2.scala @@ -0,0 +1,25 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + polyfun2(boo[Blinky]) + polyfun2(boo[Inky]) + polyfun2(boo[Pinky]) + } + + def polyfun2[G <: Blinky](p: G): Unit = { + println("polyfun2") + } +} + +object Boo extends Phantom { + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: this.Any]: B = assume +} diff --git a/tests/run/phantom-poly-3.check b/tests/run/phantom-poly-3.check new file mode 100644 index 000000000000..6bad8615924c --- /dev/null +++ b/tests/run/phantom-poly-3.check @@ -0,0 +1,3 @@ +polyfun3 +polyfun3 +polyfun3 diff --git a/tests/run/phantom-poly-3.scala b/tests/run/phantom-poly-3.scala new file mode 100644 index 000000000000..92fdced4d855 --- /dev/null +++ b/tests/run/phantom-poly-3.scala @@ -0,0 +1,26 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + polyfun3(boo[Blinky]) + polyfun3(boo[Inky]) + polyfun3(boo[Pinky]) + } + + def polyfun3[G <: BooAny, I <: G](q: I): Unit = { + println("polyfun3") + } +} + +object Boo extends Phantom { + type BooAny = this.Any + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: Blinky]: B = assume +} diff --git a/tests/run/phantom-poly-4.check b/tests/run/phantom-poly-4.check new file mode 100644 index 000000000000..db5561ee606b --- /dev/null +++ b/tests/run/phantom-poly-4.check @@ -0,0 +1,3 @@ +polyfun4 +polyfun4 +polyfun4 diff --git a/tests/run/phantom-poly-4.scala b/tests/run/phantom-poly-4.scala new file mode 100644 index 000000000000..4bd2a3127808 --- /dev/null +++ b/tests/run/phantom-poly-4.scala @@ -0,0 +1,26 @@ +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + polyfun4(boo[Blinky]) + polyfun4(boo[Inky]) + polyfun4(boo[Pinky]) + } + + def polyfun4[P >: BooNothing](p: P): Unit = { + println("polyfun4") + } +} + +object Boo extends Phantom { + type BooNothing = Boo.Nothing + type Blinky <: this.Any + type Inky <: Blinky + type Pinky <: Inky + def boo[B <: Blinky]: B = assume +} diff --git a/tests/run/phantom-val.check b/tests/run/phantom-val.check new file mode 100644 index 000000000000..06b2967cef34 --- /dev/null +++ b/tests/run/phantom-val.check @@ -0,0 +1,2 @@ +foo +1 diff --git a/tests/run/phantom-val.scala b/tests/run/phantom-val.scala new file mode 100644 index 000000000000..d6d42e008d96 --- /dev/null +++ b/tests/run/phantom-val.scala @@ -0,0 +1,26 @@ + +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + println(1) + foo + foo + + } + + val foo = { + println("foo") + any + } +} + +object Boo extends Phantom { + type BooAny = this.Any + def any: BooAny = assume +} diff --git a/tests/run/phantom-var.check b/tests/run/phantom-var.check new file mode 100644 index 000000000000..b210800439ff --- /dev/null +++ b/tests/run/phantom-var.check @@ -0,0 +1,2 @@ +foo +foo2 diff --git a/tests/run/phantom-var.scala b/tests/run/phantom-var.scala new file mode 100644 index 000000000000..dda20fe92bfe --- /dev/null +++ b/tests/run/phantom-var.scala @@ -0,0 +1,30 @@ + +/* Run this test with + * `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` + * to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. + */ + +object Test { + import Boo._ + + def main(args: Array[String]): Unit = { + foo + foo + foo = { + println("foo2") + any + } + foo + + } + + var foo = { + println("foo") + any + } +} + +object Boo extends Phantom { + type BooAny = this.Any + def any: BooAny = assume +}