From 4320e20ff5f3126940f0ecad1dd53573cf03562b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 27 Jan 2015 12:46:19 +0100 Subject: [PATCH 1/8] Fixes handling of op-assignments for polymorphic apply/update. See t3252 for a test case. --- src/dotty/tools/dotc/ast/tpd.scala | 8 ++++++++ src/dotty/tools/dotc/typer/EtaExpansion.scala | 7 +++++-- src/dotty/tools/dotc/typer/Typer.scala | 11 +++++++---- tests/{pending => }/pos/t3252.scala | 0 4 files changed, 20 insertions(+), 6 deletions(-) rename tests/{pending => }/pos/t3252.scala (100%) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 8fdc4a9db282..77c607ca7606 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -759,6 +759,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { Ident(defn.ScalaRuntimeModule.requiredMethod(name).termRef).appliedToArgs(args) } + /** An extractor that pulls out type arguments */ + object MaybePoly { + def unapply(tree: Tree): Option[(Tree, List[Tree])] = tree match { + case TypeApply(tree, targs) => Some(tree, targs) + case _ => Some(tree, Nil) + } + } + /** A traverser that passes the enlcosing class or method as an argumenr * to the traverse method. */ diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala index 6ecd90c0865d..b59748247e4b 100644 --- a/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -34,8 +34,11 @@ object EtaExpansion { * lhs += expr */ def liftAssigned(defs: mutable.ListBuffer[Tree], tree: Tree)(implicit ctx: Context): Tree = tree match { - case Apply(fn @ Select(pre, name), args) => - cpy.Apply(tree)(cpy.Select(fn)(lift(defs, pre), name), liftArgs(defs, fn.tpe, args)) + case Apply(MaybePoly(fn @ Select(pre, name), targs), args) => + cpy.Apply(tree)( + cpy.Select(fn)( + lift(defs, pre), name).appliedToTypeTrees(targs), + liftArgs(defs, fn.tpe, args)) case Select(pre, name) => cpy.Select(tree)(lift(defs, pre), name) case _ => diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index ce07ba74cba5..59aba4723bc8 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -400,10 +400,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit tree.lhs match { case lhs @ Apply(fn, args) => typed(cpy.Apply(lhs)(untpd.Select(fn, nme.update), args :+ tree.rhs), pt) - case untpd.TypedSplice(Apply(Select(fn, app), args)) if app == nme.apply => - typed(cpy.Apply(fn)( - untpd.Select(untpd.TypedSplice(fn), nme.update), - (args map untpd.TypedSplice) :+ tree.rhs), pt) + case untpd.TypedSplice(Apply(MaybePoly(Select(fn, app), targs), args)) if app == nme.apply => + val rawUpdate: untpd.Tree = untpd.Select(untpd.TypedSplice(fn), nme.update) + val wrappedUpdate = + if (targs.isEmpty) rawUpdate + else untpd.TypeApply(rawUpdate, targs map untpd.TypedSplice) + val appliedUpdate = cpy.Apply(fn)(wrappedUpdate, (args map untpd.TypedSplice) :+ tree.rhs) + typed(appliedUpdate, pt) case lhs => val lhsCore = typedUnadapted(lhs) def lhs1 = typed(untpd.TypedSplice(lhsCore)) diff --git a/tests/pending/pos/t3252.scala b/tests/pos/t3252.scala similarity index 100% rename from tests/pending/pos/t3252.scala rename to tests/pos/t3252.scala From 1f8b5691dabaae336c3c3f568b303eb24e783494 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 27 Jan 2015 12:46:48 +0100 Subject: [PATCH 2/8] Test reorg --- test/dotc/tests.scala | 2 +- .../not-representable}/pos/t3498-old.scala | 0 .../structural-type}/pos/t3175-pos.scala | 0 .../structural-type}/pos/t3363-new.scala | 2 +- .../structural-type}/pos/t3363-old.scala | 2 +- tests/neg/overrides.scala | 21 +++++++++++++ tests/pending/pos/self-type-override.scala | 13 -------- tests/pending/pos/t3278.scala | 15 ---------- tests/pending/pos/t3480.scala | 2 +- tests/{pending => }/pos/sammy_poly.scala | 0 tests/{pending => }/pos/scoping1.scala | 2 +- tests/{pending => }/pos/sealed-final.scala | 0 tests/{pending => }/pos/spec-sealed.scala | 0 tests/pos/subtyping.scala | 29 +----------------- tests/{pending => }/pos/t319.scala | 3 +- tests/pos/t3278.scala | 30 +++++++++++++++++++ tests/{pending => }/pos/t3343.scala | 0 tests/{pending => }/pos/t3411.scala | 0 tests/{pending => }/pos/t344.scala | 0 19 files changed, 59 insertions(+), 62 deletions(-) rename tests/{pending => disabled/not-representable}/pos/t3498-old.scala (100%) rename tests/{pending => disabled/structural-type}/pos/t3175-pos.scala (100%) rename tests/{pending => disabled/structural-type}/pos/t3363-new.scala (86%) rename tests/{pending => disabled/structural-type}/pos/t3363-old.scala (88%) delete mode 100644 tests/pending/pos/self-type-override.scala delete mode 100644 tests/pending/pos/t3278.scala rename tests/{pending => }/pos/sammy_poly.scala (100%) rename tests/{pending => }/pos/scoping1.scala (84%) rename tests/{pending => }/pos/sealed-final.scala (100%) rename tests/{pending => }/pos/spec-sealed.scala (100%) rename tests/{pending => }/pos/t319.scala (67%) create mode 100644 tests/pos/t3278.scala rename tests/{pending => }/pos/t3343.scala (100%) rename tests/{pending => }/pos/t3411.scala (100%) rename tests/{pending => }/pos/t344.scala (100%) diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 89ac2b6c4e45..3a863f013030 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -83,7 +83,7 @@ class tests extends CompilerTest { @Test def neg_autoTupling2 = compileFile(negDir, "autoTuplingTest", xerrors = 4) @Test def neg_companions = compileFile(negDir, "companions", xerrors = 1) @Test def neg_over = compileFile(negDir, "over", xerrors = 1) - @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 7) + @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 8) @Test def neg_projections = compileFile(negDir, "projections", xerrors = 1) @Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1) @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4) diff --git a/tests/pending/pos/t3498-old.scala b/tests/disabled/not-representable/pos/t3498-old.scala similarity index 100% rename from tests/pending/pos/t3498-old.scala rename to tests/disabled/not-representable/pos/t3498-old.scala diff --git a/tests/pending/pos/t3175-pos.scala b/tests/disabled/structural-type/pos/t3175-pos.scala similarity index 100% rename from tests/pending/pos/t3175-pos.scala rename to tests/disabled/structural-type/pos/t3175-pos.scala diff --git a/tests/pending/pos/t3363-new.scala b/tests/disabled/structural-type/pos/t3363-new.scala similarity index 86% rename from tests/pending/pos/t3363-new.scala rename to tests/disabled/structural-type/pos/t3363-new.scala index f935cfe1a363..835d9471b922 100644 --- a/tests/pending/pos/t3363-new.scala +++ b/tests/disabled/structural-type/pos/t3363-new.scala @@ -7,7 +7,7 @@ object TestCase { //if fs was reduced to List (generic type with one parameter) then the code compiles //if you inherit from MapOps[T] instead of MapOps[F] then code compiles fine - implicit def map2ops[T,F](fs: Map[T,F]): TestCase.MapOps[F]{lazy val m: reflect.runtime.universe.TypeTag[T]; def is(xs: List[T]): List[List[T]]} = new MapOps[F] { + implicit def map2ops[T,F](fs: Map[T,F]): TestCase.MapOps[F]{val m: reflect.runtime.universe.TypeTag[T]; def is(xs: List[T]): List[List[T]]} = new MapOps[F] { //if you remove this line, then code compiles lazy val m: TypeTag[T] = sys.error("just something to make it compile") def is(xs: List[T]) = List(xs) diff --git a/tests/pending/pos/t3363-old.scala b/tests/disabled/structural-type/pos/t3363-old.scala similarity index 88% rename from tests/pending/pos/t3363-old.scala rename to tests/disabled/structural-type/pos/t3363-old.scala index 8e54d4b4a8c3..0088eff3dc54 100644 --- a/tests/pending/pos/t3363-old.scala +++ b/tests/disabled/structural-type/pos/t3363-old.scala @@ -5,7 +5,7 @@ object TestCase { //if fs was reduced to List (generic type with one parameter) then the code compiles //if you inherit from MapOps[T] instead of MapOps[F] then code compiles fine - implicit def map2ops[T,F](fs: Map[T,F]): TestCase.MapOps[F]{lazy val m: Manifest[T]; def is(xs: List[T]): List[List[T]]} = new MapOps[F] { + implicit def map2ops[T,F](fs: Map[T,F]): TestCase.MapOps[F]{val m: Manifest[T]; def is(xs: List[T]): List[List[T]]} = new MapOps[F] { //if you remove this line, then code compiles lazy val m: Manifest[T] = sys.error("just something to make it compile") def is(xs: List[T]) = List(xs) diff --git a/tests/neg/overrides.scala b/tests/neg/overrides.scala index 943cc8bc4fda..cffb5480aa45 100644 --- a/tests/neg/overrides.scala +++ b/tests/neg/overrides.scala @@ -79,3 +79,24 @@ class Y2 extends X2 { class X3 { override type T = A1 } + +package p3 { + +// Dotty change of rules: Toverrider#f does not +// override TCommon#f, hence the accidental override rule +// applies. +trait TCommon { + def f: String +} + +class C1 extends TCommon { + def f = "in C1" +} + +trait TOverrider { this: TCommon => + override def f = "in TOverrider" // The overridden self-type member... +} + +class C2 extends C1 with TOverrider // ... fails to override, here. + +} diff --git a/tests/pending/pos/self-type-override.scala b/tests/pending/pos/self-type-override.scala deleted file mode 100644 index 7c40ef37e69c..000000000000 --- a/tests/pending/pos/self-type-override.scala +++ /dev/null @@ -1,13 +0,0 @@ -trait TCommon { - def f: String -} - -class C1 extends TCommon { - def f = "in C1" -} - -trait TOverrider { this: TCommon => - override def f = "in TOverrider" // The overridden self-type member... -} - -class C2 extends C1 with TOverrider // ... fails to override, here. diff --git a/tests/pending/pos/t3278.scala b/tests/pending/pos/t3278.scala deleted file mode 100644 index 458070c5e7e7..000000000000 --- a/tests/pending/pos/t3278.scala +++ /dev/null @@ -1,15 +0,0 @@ -class Foo -class Test { - def update[B](x : B, b : Int): Unit = {} - def apply[B](x : B) = 1 -} - -object Test { - def main(a : Array[String]): Unit = { - val a = new Test - val f = new Foo - a(f) = 1 //works - a(f) = a(f) + 1 //works - a(f) += 1 //error: reassignment to val - } -} diff --git a/tests/pending/pos/t3480.scala b/tests/pending/pos/t3480.scala index d9a092e8a66a..f04ea2933370 100644 --- a/tests/pending/pos/t3480.scala +++ b/tests/pending/pos/t3480.scala @@ -1,4 +1,4 @@ object Test { - val List(_*) = List(1) + val List(_: _*) = List(1) val Array( who, what : _* ) = "Eclipse plugin cannot not handle this" split (" ") } diff --git a/tests/pending/pos/sammy_poly.scala b/tests/pos/sammy_poly.scala similarity index 100% rename from tests/pending/pos/sammy_poly.scala rename to tests/pos/sammy_poly.scala diff --git a/tests/pending/pos/scoping1.scala b/tests/pos/scoping1.scala similarity index 84% rename from tests/pending/pos/scoping1.scala rename to tests/pos/scoping1.scala index 9fe1b5f3e5b7..83ad1357ae86 100644 --- a/tests/pending/pos/scoping1.scala +++ b/tests/pos/scoping1.scala @@ -2,7 +2,7 @@ object This extends App { trait A { def foo(): Unit } - class C { self: A => + abstract class C { self: A => def bar() = this.foo() } class D extends C with A { diff --git a/tests/pending/pos/sealed-final.scala b/tests/pos/sealed-final.scala similarity index 100% rename from tests/pending/pos/sealed-final.scala rename to tests/pos/sealed-final.scala diff --git a/tests/pending/pos/spec-sealed.scala b/tests/pos/spec-sealed.scala similarity index 100% rename from tests/pending/pos/spec-sealed.scala rename to tests/pos/spec-sealed.scala diff --git a/tests/pos/subtyping.scala b/tests/pos/subtyping.scala index 29d830dd2c8b..e65bdd16f027 100644 --- a/tests/pos/subtyping.scala +++ b/tests/pos/subtyping.scala @@ -1,32 +1,5 @@ -class A { - def test1(): Unit = { - implicitly[this.type <:< this.type] - implicitly[this.type <:< A] - } -} object test { - def tag1[T](x: T): String & T = ??? - def tag2[T](x: T): T & String = ??? - - val x1: Int & String = tag1(0) - val x2: Int & String = tag2(0) - val x3: String & Int = tag1(0) - val x4: String & Int = tag2(0) - -} - -object test2 { - - class A - class B - - val x: A | B = ??? - val y: B | A = x - - val a: A & B = ??? - val b: B & A = a + val x: Int = 1 } - - diff --git a/tests/pending/pos/t319.scala b/tests/pos/t319.scala similarity index 67% rename from tests/pending/pos/t319.scala rename to tests/pos/t319.scala index eed25eb84ce6..5c06f4db06ec 100644 --- a/tests/pending/pos/t319.scala +++ b/tests/pos/t319.scala @@ -14,7 +14,8 @@ object test { val a = new A { type T = String }; /** val b: B { type T = String } = functor(a) */ val b: B { type T = String } = { - val tmp = new functor() { val arg = a }; + val tmp = new functor() { val arg: A { type T = String } = a }; + // Dotty deviaton: arg needs an explicit type here, or else the inherited type `A` would be assumed. tmp.res } diff --git a/tests/pos/t3278.scala b/tests/pos/t3278.scala new file mode 100644 index 000000000000..05bfbc1463a5 --- /dev/null +++ b/tests/pos/t3278.scala @@ -0,0 +1,30 @@ +class Foo +class Test { + def update[B](x : B, b : Int): Unit = {} + def apply[B](x : B) = 1 +} +class Test2 { + type B = Foo + def update(x : B, b : Int): Unit = {} + def apply(x : B) = 1 +} + +object Test { + def main(a : Array[String]): Unit = { + val a = new Test + val f = new Foo + a(f) = 1 //works + a(f) = a(f) + 1 //works + a(f) += 1 //error: reassignment to val + } +} +object Test2 { + def main(args : Array[String]): Unit = { + args(0) += "a" + val a = new Test2 + val f = new Foo + a(f) = 1 //works + a(f) = a(f) + 1 //works + a(f) += 1 //error: reassignment to val + } +} diff --git a/tests/pending/pos/t3343.scala b/tests/pos/t3343.scala similarity index 100% rename from tests/pending/pos/t3343.scala rename to tests/pos/t3343.scala diff --git a/tests/pending/pos/t3411.scala b/tests/pos/t3411.scala similarity index 100% rename from tests/pending/pos/t3411.scala rename to tests/pos/t3411.scala diff --git a/tests/pending/pos/t344.scala b/tests/pos/t344.scala similarity index 100% rename from tests/pending/pos/t344.scala rename to tests/pos/t344.scala From 43ee240c3db3820cecb23ab22c93b1df2412cdc8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 27 Jan 2015 15:27:49 +0100 Subject: [PATCH 3/8] Fix of #329. Overriding pairs needs to match ExprTypes with field types. Closes #329. --- src/dotty/tools/dotc/transform/OverridingPairs.scala | 2 +- test/dotc/tests.scala | 4 ++-- tests/neg/overrides.scala | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/dotty/tools/dotc/transform/OverridingPairs.scala b/src/dotty/tools/dotc/transform/OverridingPairs.scala index f631dcf9a2c5..4026749b2c97 100644 --- a/src/dotty/tools/dotc/transform/OverridingPairs.scala +++ b/src/dotty/tools/dotc/transform/OverridingPairs.scala @@ -43,7 +43,7 @@ object OverridingPairs { val info1 = self.memberInfo(sym1) val info2 = self.memberInfo(sym2) // info1.signature == info2.signature && // TODO enable for speed - info1 matches info2 + info1.widenExpr matches info2.widenExpr } /** The symbols that can take part in an overriding pair */ diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 3a863f013030..27c4c6cd08ad 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -82,8 +82,8 @@ class tests extends CompilerTest { @Test def neg_autoTupling = compileFile(posDir, "autoTuplingTest", "-language:noAutoTupling" :: Nil, xerrors = 4) @Test def neg_autoTupling2 = compileFile(negDir, "autoTuplingTest", xerrors = 4) @Test def neg_companions = compileFile(negDir, "companions", xerrors = 1) - @Test def neg_over = compileFile(negDir, "over", xerrors = 1) - @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 8) + @Test def neg_over = compileFile(negDir, "over", xerrors = 2) + @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 9) @Test def neg_projections = compileFile(negDir, "projections", xerrors = 1) @Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1) @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4) diff --git a/tests/neg/overrides.scala b/tests/neg/overrides.scala index cffb5480aa45..8eddda68fc2b 100644 --- a/tests/neg/overrides.scala +++ b/tests/neg/overrides.scala @@ -100,3 +100,10 @@ trait TOverrider { this: TCommon => class C2 extends C1 with TOverrider // ... fails to override, here. } + +package p4 { + + abstract class C[T] { def head: T } + case class D[T](head: Int) extends C[T] + +} From 945576e421e5f7dc82984c4673884ad4c7ddf969 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 27 Jan 2015 17:38:18 +0100 Subject: [PATCH 4/8] New spec and implementation for matching. Reformulated matchign spec and implemented accordingly. Previous fix for #329 would have missed third new error case in over.scala. --- src/dotty/tools/dotc/core/TypeComparer.scala | 41 +++++++------------ src/dotty/tools/dotc/core/Types.scala | 16 +++++--- .../dotc/transform/OverridingPairs.scala | 4 +- test/dotc/tests.scala | 2 +- tests/neg/over.scala | 8 ++++ 5 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index b40baafdf967..1687d6159f88 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -648,45 +648,34 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi // Tests around `matches` /** A function implementing `tp1` matches `tp2`. */ - final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = tp1 match { + final def matchesType(tp1: Type, tp2: Type, relaxed: Boolean): Boolean = tp1.widen match { case tp1: MethodType => - tp2 match { + tp2.widen match { case tp2: MethodType => tp1.isImplicit == tp2.isImplicit && matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) && - matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), alwaysMatchSimple) - case tp2: ExprType => - tp1.paramNames.isEmpty && - matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple) - case _ => - false - } - case tp1: ExprType => - tp2 match { - case tp2: MethodType => - tp2.paramNames.isEmpty && - matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple) - case tp2: ExprType => - matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple) - case _ => - false // was: matchesType(tp1.resultType, tp2, alwaysMatchSimple) + matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed) + case tp2 => + relaxed && tp1.paramNames.isEmpty && + matchesType(tp1.resultType, tp2, relaxed) } case tp1: PolyType => - tp2 match { + tp2.widen match { case tp2: PolyType => sameLength(tp1.paramNames, tp2.paramNames) && - matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), alwaysMatchSimple) + matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed) case _ => false } case _ => - tp2 match { - case _: MethodType | _: PolyType => + tp2.widen match { + case _: PolyType => false - case tp2: ExprType => - false // was: matchesType(tp1, tp2.resultType, alwaysMatchSimple) - case _ => - alwaysMatchSimple || isSameType(tp1, tp2) + case tp2: MethodType => + relaxed && tp2.paramNames.isEmpty && + matchesType(tp1, tp2.resultType, relaxed) + case tp2 => + relaxed || isSameType(tp1, tp2) } } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 6c87d44e6bc8..e759c3ad3015 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -598,17 +598,21 @@ object Types { * - Either both types are polytypes with the same number of * type parameters and their result types match after renaming * corresponding type parameters - * - Or both types are (possibly nullary) method types with equivalent parameter types - * and matching result types - * - Or both types are equivalent - * - Or phase.erasedTypes is false and both types are neither method nor - * poly types. + * - Or both types are method types with =:=-equivalent(*) parameter types + * and matching result types after renaming corresponding parameter types + * if the method types are dependent. + * - Or both types are =:=-equivalent + * - Or phase.erasedTypes is false, and neither type takes + * term or type parameters. + * + * (*) when matching with a Java method, we also regard Any and Object as equivalent + * parameter types. */ def matches(that: Type)(implicit ctx: Context): Boolean = if (Config.newMatch) this.signature matches that.signature else track("matches") { ctx.typeComparer.matchesType( - this, that, alwaysMatchSimple = !ctx.phase.erasedTypes) + this, that, relaxed = !ctx.phase.erasedTypes) } /** This is the same as `matches` except that it also matches => T with T and diff --git a/src/dotty/tools/dotc/transform/OverridingPairs.scala b/src/dotty/tools/dotc/transform/OverridingPairs.scala index 4026749b2c97..bad763f41a44 100644 --- a/src/dotty/tools/dotc/transform/OverridingPairs.scala +++ b/src/dotty/tools/dotc/transform/OverridingPairs.scala @@ -42,8 +42,8 @@ object OverridingPairs { sym1.isType || { val info1 = self.memberInfo(sym1) val info2 = self.memberInfo(sym2) - // info1.signature == info2.signature && // TODO enable for speed - info1.widenExpr matches info2.widenExpr + info1.signature.sameParams(info2.signature) && + info1.matches(info2) } /** The symbols that can take part in an overriding pair */ diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 27c4c6cd08ad..4c617c035ce3 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -82,7 +82,7 @@ class tests extends CompilerTest { @Test def neg_autoTupling = compileFile(posDir, "autoTuplingTest", "-language:noAutoTupling" :: Nil, xerrors = 4) @Test def neg_autoTupling2 = compileFile(negDir, "autoTuplingTest", xerrors = 4) @Test def neg_companions = compileFile(negDir, "companions", xerrors = 1) - @Test def neg_over = compileFile(negDir, "over", xerrors = 2) + @Test def neg_over = compileFile(negDir, "over", xerrors = 3) @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 9) @Test def neg_projections = compileFile(negDir, "projections", xerrors = 1) @Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1) diff --git a/tests/neg/over.scala b/tests/neg/over.scala index 488d71614c3c..80ce7d09f4c3 100644 --- a/tests/neg/over.scala +++ b/tests/neg/over.scala @@ -8,3 +8,11 @@ class C extends T { override val y = 2 } + +class D extends T { + + def x(): String = "" + +} + + From 86735bf73de4a165a46ce6215af2e7a814adb9f4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 28 Jan 2015 16:31:42 +0100 Subject: [PATCH 5/8] Tweaks to matches 1) Drop redundant signature comparison in overriding pairs 2) Abstract from repeated parameters when calculating matches --- src/dotty/tools/dotc/core/TypeApplications.scala | 2 +- src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- src/dotty/tools/dotc/transform/OverridingPairs.scala | 7 +------ 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 998b4f9444da..4a16ca45d62c 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -285,7 +285,7 @@ class TypeApplications(val self: Type) extends AnyVal { */ def underlyingIfRepeated(isJava: Boolean)(implicit ctx: Context): Type = if (self.isRepeatedParam) { - val seqClass = if(isJava) defn.ArrayClass else defn.SeqClass + val seqClass = if (isJava) defn.ArrayClass else defn.SeqClass translateParameterized(defn.RepeatedParamClass, seqClass) } else self diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 1687d6159f88..75f7c592216c 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -684,7 +684,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi case formal1 :: rest1 => formals2 match { case formal2 :: rest2 => - (isSameType(formal1, formal2) + (isSameType(formal1.underlyingIfRepeated(isJava1), formal2.underlyingIfRepeated(isJava2)) || isJava1 && (formal2 isRef ObjectClass) && (formal1 isRef AnyClass) || isJava2 && (formal1 isRef ObjectClass) && (formal2 isRef AnyClass)) && matchingParams(rest1, rest2, isJava1, isJava2) diff --git a/src/dotty/tools/dotc/transform/OverridingPairs.scala b/src/dotty/tools/dotc/transform/OverridingPairs.scala index bad763f41a44..650a03054e05 100644 --- a/src/dotty/tools/dotc/transform/OverridingPairs.scala +++ b/src/dotty/tools/dotc/transform/OverridingPairs.scala @@ -39,12 +39,7 @@ object OverridingPairs { * relative to .this do */ protected def matches(sym1: Symbol, sym2: Symbol): Boolean = - sym1.isType || { - val info1 = self.memberInfo(sym1) - val info2 = self.memberInfo(sym2) - info1.signature.sameParams(info2.signature) && - info1.matches(info2) - } + sym1.isType || self.memberInfo(sym1).matches(self.memberInfo(sym2)) /** The symbols that can take part in an overriding pair */ private val decls = { From fb6d1f5f41ac07c7b0ce5105c410455c92945f19 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 29 Jan 2015 15:34:49 +0100 Subject: [PATCH 6/8] More negative override tests --- test/dotc/tests.scala | 2 +- tests/neg/overrides.scala | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 4c617c035ce3..21fdd555bdd5 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -83,7 +83,7 @@ class tests extends CompilerTest { @Test def neg_autoTupling2 = compileFile(negDir, "autoTuplingTest", xerrors = 4) @Test def neg_companions = compileFile(negDir, "companions", xerrors = 1) @Test def neg_over = compileFile(negDir, "over", xerrors = 3) - @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 9) + @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 11) @Test def neg_projections = compileFile(negDir, "projections", xerrors = 1) @Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1) @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4) diff --git a/tests/neg/overrides.scala b/tests/neg/overrides.scala index 8eddda68fc2b..9fe06d93020c 100644 --- a/tests/neg/overrides.scala +++ b/tests/neg/overrides.scala @@ -107,3 +107,17 @@ package p4 { case class D[T](head: Int) extends C[T] } + +package p5 { +class A { + def m: String = "foo" +} + +class B extends A { + override val m: Int = 42 +} + +class C extends A { + override def m: Int = 42 +} +} From a469fa849cdb2ed1310731de05cfa9ee5d286170 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 31 Jan 2015 19:03:51 +0100 Subject: [PATCH 7/8] New failing test As noticed by @retronym, Any and Object are not identified when matching Scala and Java methods. I believe this is because the Java method does not have the Java flag set. @olhotak can you take a look? --- tests/pending/pos/java-override/A.java | 3 +++ tests/pending/pos/java-override/B.scala | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/pending/pos/java-override/A.java create mode 100644 tests/pending/pos/java-override/B.scala diff --git a/tests/pending/pos/java-override/A.java b/tests/pending/pos/java-override/A.java new file mode 100644 index 000000000000..0d7f453e8554 --- /dev/null +++ b/tests/pending/pos/java-override/A.java @@ -0,0 +1,3 @@ +public interface A { + void o(Object o); +} diff --git a/tests/pending/pos/java-override/B.scala b/tests/pending/pos/java-override/B.scala new file mode 100644 index 000000000000..cb4addbcce81 --- /dev/null +++ b/tests/pending/pos/java-override/B.scala @@ -0,0 +1,7 @@ +//trait T { def t(o: Object): Unit } + +class B extends A /*with T*/ { + override def o(o: Any): Unit = () + + //override def t(o: AnyRef): Unit = () +} From 976ed6fd0aa4f0dd3da54889c4d85ef856f6531f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 31 Jan 2015 19:10:13 +0100 Subject: [PATCH 8/8] Revert following underlyingIfRepeated when matching This was a left-over from a failed attempt to have OverridingPiars work exclusively by comparing signatures. If we do that then repeated and underlying do have the same signature and therefore are supposed to match. But as @retronym notes, this leads to problems. In any case, we no longer try to make overriding pairs work that way, because it fails for other reasons as well. --- src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 75f7c592216c..1687d6159f88 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -684,7 +684,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi case formal1 :: rest1 => formals2 match { case formal2 :: rest2 => - (isSameType(formal1.underlyingIfRepeated(isJava1), formal2.underlyingIfRepeated(isJava2)) + (isSameType(formal1, formal2) || isJava1 && (formal2 isRef ObjectClass) && (formal1 isRef AnyClass) || isJava2 && (formal1 isRef ObjectClass) && (formal2 isRef AnyClass)) && matchingParams(rest1, rest2, isJava1, isJava2)