diff --git a/src/dotty/tools/backend/jvm/CollectEntryPoints.scala b/src/dotty/tools/backend/jvm/CollectEntryPoints.scala index 802100bf25ad..734890daa2e1 100644 --- a/src/dotty/tools/backend/jvm/CollectEntryPoints.scala +++ b/src/dotty/tools/backend/jvm/CollectEntryPoints.scala @@ -48,14 +48,22 @@ class CollectEntryPoints extends MiniPhaseTransform { } object CollectEntryPoints{ + def isJavaMainMethod(sym: Symbol)(implicit ctx: Context) = { + val d = ctx.definitions + val StringType = d.StringType + + (sym.name == nme.main) && (sym.info match { + case r@MethodType(_, List(d.ArrayType(t))) => + (t.widenDealias =:= StringType) && ( + r.resultType.widenDealias =:= d.UnitType) + case _ => false + }) + } + def isJavaEntyPoint(sym: Symbol)(implicit ctx: Context): Boolean = { import Types.MethodType val d = ctx.definitions val StringType = d.StringType - def isJavaMainMethod(sym: Symbol) = (sym.name == nme.main) && (toDenot(sym).info match { - case r@ MethodType(_, List(d.ArrayType(StringType))) => r.resultType eq d.UnitType - case _ => false - }) // The given class has a main method. def hasJavaMainMethod(sym: Symbol): Boolean = (toDenot(sym).info member nme.main).alternatives exists(x => isJavaMainMethod(x.symbol)) diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 5fcb7f57be97..357018857cce 100644 --- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -452,7 +452,8 @@ class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{ def isVarargsMethod: Boolean = sym is Flags.JavaVarargs def isDeprecated: Boolean = false def isMutable: Boolean = sym is Flags.Mutable - def hasAbstractFlag: Boolean = (sym is Flags.Abstract) || (sym is Flags.JavaInterface) + def hasAbstractFlag: Boolean = + (sym is Flags.Abstract) || (sym is Flags.JavaInterface) || (sym is Flags.Trait) def hasModuleFlag: Boolean = sym is Flags.Module def isSynchronized: Boolean = sym is Flags.Synchronized def isNonBottomSubClass(other: Symbol): Boolean = sym.derivesFrom(other) diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index e051e16c8d49..0db8a42c984e 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -67,7 +67,7 @@ class Compiler { List(new LambdaLift, new Flatten, new RestoreScopes), - List(/*new PrivateToStatic,*/ new CollectEntryPoints, new LabelDefs, new ElimWildcardIdents), + List(/*new PrivateToStatic,*/ new CollectEntryPoints, new LabelDefs, new ElimWildcardIdents, new TraitConstructors), List(new GenBCode) ) diff --git a/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/src/dotty/tools/dotc/transform/InterceptedMethods.scala index b39405ba3cc5..87a5c1a4ca23 100644 --- a/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -64,14 +64,14 @@ class InterceptedMethods extends MiniPhaseTransform { thisTransform => // this should be removed if we have guarantee that ## will get Apply node override def transformSelect(tree: tpd.Select)(implicit ctx: Context, info: TransformerInfo): Tree = { if (tree.symbol.isTerm && poundPoundMethods.contains(tree.symbol.asTerm)) { - val rewrite = PoundPoundValue(tree.qualifier) + val rewrite = poundPoundValue(tree.qualifier) ctx.log(s"$phaseName rewrote $tree to $rewrite") rewrite } else tree } - private def PoundPoundValue(tree: Tree)(implicit ctx: Context) = { + private def poundPoundValue(tree: Tree)(implicit ctx: Context) = { val s = tree.tpe.widen.typeSymbol if (s == defn.NullClass) Literal(Constant(0)) else { @@ -108,7 +108,7 @@ class InterceptedMethods extends MiniPhaseTransform { thisTransform => val rewrite: Tree = tree.fun match { case Select(qual, name) => if (poundPoundMethods contains tree.fun.symbol.asTerm) { - PoundPoundValue(qual) + poundPoundValue(qual) } else if (Any_comparisons contains tree.fun.symbol.asTerm) { if (tree.fun.symbol eq defn.Any_==) { qual.select(defn.Any_equals).appliedToArgs(tree.args) diff --git a/src/dotty/tools/dotc/transform/TraitConstructors.scala b/src/dotty/tools/dotc/transform/TraitConstructors.scala new file mode 100644 index 000000000000..8c92f1f7bf05 --- /dev/null +++ b/src/dotty/tools/dotc/transform/TraitConstructors.scala @@ -0,0 +1,37 @@ +package dotty.tools.dotc.transform + +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.core.DenotTransformers.{SymTransformer, DenotTransformer} +import dotty.tools.dotc.core.Denotations.SingleDenotation +import dotty.tools.dotc.core.Phases.Phase +import dotty.tools.dotc.core.StdNames._ +import dotty.tools.dotc.core.SymDenotations.SymDenotation +import dotty.tools.dotc.core._ +import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo} + +/*** + * Renames constructors in traits so that backend will call them with invokeInterface + * Also makes sure that renamed constructor bodies conforms to type of method + */ +class TraitConstructors extends MiniPhaseTransform with SymTransformer { + import dotty.tools.dotc.ast.tpd._ + def phaseName: String = "traitConstructors" + + + override def treeTransformPhase: Phase = this.phase + + def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = { + if(sym.isPrimaryConstructor && (sym.owner is Flags.Trait)) + sym.copySymDenotation(name = nme.INITIALIZER_PREFIX ++ sym.owner.fullName) + else sym + } + + override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { + val sym = tree.symbol + if (sym.isPrimaryConstructor && (sym.owner is Flags.Trait)) + cpy.DefDef(tree)(rhs = Block(List(tree.rhs), This(tree.symbol.enclosingClass.asClass))) + else tree + } + +} diff --git a/tests/pos/approximateUnion.scala b/tests/pos/approximateUnion.scala index c3fe0e1625f5..d23c3ca0ee04 100644 --- a/tests/pos/approximateUnion.scala +++ b/tests/pos/approximateUnion.scala @@ -10,8 +10,8 @@ object approximateUnion { trait B extends C[B] with D val coin = true - val x = if (coin) new A else new B - val y = Some(if (coin) new A else new B) + val x = if (coin) new A{} else new B{} + val y = Some(if (coin) new A{} else new B{} ) val xtest: C[A | B] & D = x val ytest: Some[C[A | B] & D] = y @@ -22,8 +22,8 @@ object approximateUnion { trait B extends C[X[B]] with D with E val coin = true - val x = if (coin) new A else new B - val y = Some(if (coin) new A else new B) + val x = if (coin) new A{} else new B{} + val y = Some(if (coin) new A{} else new B{}) val xtest: C[X[A & B]] & D = x val ytest: Some[C[X[A & B]] & D] = y @@ -42,8 +42,8 @@ object approximateUnion2 { trait B extends C[B] with D val coin = true - val x = if (coin) new A else new B - val y = Some(if (coin) new A else new B) + val x = if (coin) new A{} else new B{} + val y = Some(if (coin) new A{} else new B{}) val xtest: C[_ >: A & B <: A | B] & D = x val ytest: Some[C[_ >: A & B <: A | B] & D] = y @@ -54,8 +54,8 @@ object approximateUnion2 { trait B extends C[X[B]] with D with E val coin = true - val x = if (coin) new A else new B - val y = Some(if (coin) new A else new B) + val x = if (coin) new A{} else new B{} + val y = Some(if (coin) new A{} else new B{}) val xtest: C[_ >: X[A | B] <: X[A & B]] & D = x val ytest: Some[C[_ >: X[A | B] <: X[A & B]]] = y @@ -74,8 +74,8 @@ object approximateUnion3 { trait B extends C[B] with D val coin = true - val x = if (coin) new A else new B - val y = Some(if (coin) new A else new B) + val x = if (coin) new A{} else new B{} + val y = Some(if (coin) new A{} else new B{}) val xtest: C[A & B] & D = x val ytest: Some[C[A & B] & D] = y @@ -86,8 +86,8 @@ object approximateUnion3 { trait B extends C[X[B]] with D with E val coin = true - val x = if (coin) new A else new B - val y = Some(if (coin) new A else new B) + val x = if (coin) new A{} else new B{} + val y = Some(if (coin) new A{} else new B{}) val xtest: C[X[A | B]] & D = x val ytest2: Some[C[X[A | B]] & D] = y