diff options
30 files changed, 146 insertions, 108 deletions
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 8fdc4a9db..77c607ca7 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/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 998b4f944..4a16ca45d 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 b40baafdf..1687d6159 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 6c87d44e6..e759c3ad3 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 f631dcf9a..650a03054 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 <base>.this do */ protected def matches(sym1: Symbol, sym2: Symbol): Boolean = - sym1.isType || { - val info1 = self.memberInfo(sym1) - val info2 = self.memberInfo(sym2) - // info1.signature == info2.signature && // TODO enable for speed - 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 = { diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala index 6ecd90c08..b59748247 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 ce07ba74c..59aba4723 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/test/dotc/tests.scala b/test/dotc/tests.scala index 89ac2b6c4..21fdd555b 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 = 7) + @Test def neg_over = compileFile(negDir, "over", xerrors = 3) + @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/pending/pos/t3498-old.scala b/tests/disabled/not-representable/pos/t3498-old.scala index 118a8d849..118a8d849 100644 --- a/tests/pending/pos/t3498-old.scala +++ b/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 index 89bbf8b5f..89bbf8b5f 100644 --- a/tests/pending/pos/t3175-pos.scala +++ b/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 index f935cfe1a..835d9471b 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 index 8e54d4b4a..0088eff3d 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/over.scala b/tests/neg/over.scala index 488d71614..80ce7d09f 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 = "" + +} + + diff --git a/tests/neg/overrides.scala b/tests/neg/overrides.scala index 943cc8bc4..9fe06d930 100644 --- a/tests/neg/overrides.scala +++ b/tests/neg/overrides.scala @@ -79,3 +79,45 @@ 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. + +} + +package p4 { + + abstract class C[T] { def head: T } + 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 +} +} diff --git a/tests/pending/pos/java-override/A.java b/tests/pending/pos/java-override/A.java new file mode 100644 index 000000000..0d7f453e8 --- /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 000000000..cb4addbcc --- /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 = () +} diff --git a/tests/pending/pos/self-type-override.scala b/tests/pending/pos/self-type-override.scala deleted file mode 100644 index 7c40ef37e..000000000 --- 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 458070c5e..000000000 --- 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 d9a092e8a..f04ea2933 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 index f43fa292c..f43fa292c 100644 --- a/tests/pending/pos/sammy_poly.scala +++ b/tests/pos/sammy_poly.scala diff --git a/tests/pending/pos/scoping1.scala b/tests/pos/scoping1.scala index 9fe1b5f3e..83ad1357a 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 index bdedb5c1f..bdedb5c1f 100644 --- a/tests/pending/pos/sealed-final.scala +++ b/tests/pos/sealed-final.scala diff --git a/tests/pending/pos/spec-sealed.scala b/tests/pos/spec-sealed.scala index d7ecfaaab..d7ecfaaab 100644 --- a/tests/pending/pos/spec-sealed.scala +++ b/tests/pos/spec-sealed.scala diff --git a/tests/pos/subtyping.scala b/tests/pos/subtyping.scala index 29d830dd2..e65bdd16f 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 index eed25eb84..5c06f4db0 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/pending/pos/t3252.scala b/tests/pos/t3252.scala index 3ecc1e7ce..3ecc1e7ce 100644 --- a/tests/pending/pos/t3252.scala +++ b/tests/pos/t3252.scala diff --git a/tests/pos/t3278.scala b/tests/pos/t3278.scala new file mode 100644 index 000000000..05bfbc146 --- /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 index 9d1bc9355..9d1bc9355 100644 --- a/tests/pending/pos/t3343.scala +++ b/tests/pos/t3343.scala diff --git a/tests/pending/pos/t3411.scala b/tests/pos/t3411.scala index 6d46be4e4..6d46be4e4 100644 --- a/tests/pending/pos/t3411.scala +++ b/tests/pos/t3411.scala diff --git a/tests/pending/pos/t344.scala b/tests/pos/t344.scala index 449a763af..449a763af 100644 --- a/tests/pending/pos/t344.scala +++ b/tests/pos/t344.scala |