From 27cd90f6bf889f3c111c00845a06cbc87d5871a8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 27 Jan 2015 12:46:19 +0100 Subject: [PATCH 01/10] 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 9958b3b64ca2..683d457d08a3 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 4aa6b7a4d5f8d2d64d3beea0bd97848104434d65 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 27 Jan 2015 12:46:48 +0100 Subject: [PATCH 02/10] 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 79d782de8d9f45d38021802aed27146d6e6ba300 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 27 Jan 2015 15:27:49 +0100 Subject: [PATCH 03/10] 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 bc3c085a92a6..4aa314906743 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 e2f9fb08a4c0de14dd01c99cbe13cedb9e8aee62 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 27 Jan 2015 17:38:18 +0100 Subject: [PATCH 04/10] 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 | 18 ++++---- .../dotc/transform/OverridingPairs.scala | 4 +- test/dotc/tests.scala | 2 +- tests/neg/over.scala | 8 ++++ 5 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 9d6acee71496..ce6787c1ea28 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -644,45 +644,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 ef8aa78b63dd..4e8bd5ed9671 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -593,22 +593,26 @@ object Types { } /** Is this type close enough to that type so that members - * with the two type would override each other?d + * with the two type would override each other? * This means: * - 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 4aa314906743..5921dd46f077 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 2514c3b0cb0c29555989dc0a87620356678171fd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 28 Jan 2015 16:31:42 +0100 Subject: [PATCH 05/10] 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 e59c6095945b..7e23c7fff627 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 ce6787c1ea28..358e82adbf12 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -680,7 +680,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 5921dd46f077..f7adec471541 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 eeee941335ef1eaf37ed11107783fe26a8ebdf09 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 29 Jan 2015 15:34:49 +0100 Subject: [PATCH 06/10] 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 122cef8ffd976feabe3624d28ca0dfad54f6cb21 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 31 Jan 2015 19:03:51 +0100 Subject: [PATCH 07/10] 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 7df36a3d492d47e308154b8874a938b2b4134e34 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 31 Jan 2015 19:10:13 +0100 Subject: [PATCH 08/10] 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 358e82adbf12..ce6787c1ea28 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -680,7 +680,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) From d9a013c34907018fae11b3ba43dd46b75a43c62b Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Mon, 2 Feb 2015 09:59:15 +0100 Subject: [PATCH 09/10] Java methods: JavaMethodType instead of MethodType, convert Object to Any Fixes two bugs needed for java-override test: Namer was creating a MethodType instead of a JavaMethodType even though the JavaDefined flag was set on the DefDef. Following Scalac, Namer needs to convert Java method parameters of type j.l.Object to s.Any. --- src/dotty/tools/dotc/typer/Namer.scala | 5 +++++ test/dotc/tests.scala | 1 + tests/{pending => }/pos/java-override/A.java | 0 tests/{pending => }/pos/java-override/B.scala | 0 4 files changed, 6 insertions(+) rename tests/{pending => }/pos/java-override/A.java (100%) rename tests/{pending => }/pos/java-override/B.scala (100%) diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 323a1100ba1f..63961319a8fe 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -654,9 +654,14 @@ class Namer { typer: Typer => else restpe val monotpe = (paramSymss :\ restpe1) { (params, restpe) => + val isJava = ddef.mods is JavaDefined val make = if (params.nonEmpty && (params.head is Implicit)) ImplicitMethodType + else if(isJava) JavaMethodType else MethodType + if(isJava) params.foreach { symbol => + if(symbol.info.isDirectRef(defn.ObjectClass)) symbol.info = defn.AnyType + } make.fromSymbols(params, restpe) } if (typeParams.nonEmpty) PolyType.fromSymbols(typeParams, monotpe) diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 21fdd555bdd5..524f3ce12dc9 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -57,6 +57,7 @@ class tests extends CompilerTest { @Test def pos_packageobject() = compileFile(posDir, "packageobject") @Test def pos_overloaded() = compileFile(posDir, "overloaded") @Test def pos_overrides() = compileFile(posDir, "overrides") + @Test def pos_javaOverride() = compileDir(posDir + "java-override") @Test def pos_templateParents() = compileFile(posDir, "templateParents") @Test def pos_structural() = compileFile(posDir, "structural") @Test def pos_overloadedAccess = compileFile(posDir, "overloadedAccess") diff --git a/tests/pending/pos/java-override/A.java b/tests/pos/java-override/A.java similarity index 100% rename from tests/pending/pos/java-override/A.java rename to tests/pos/java-override/A.java diff --git a/tests/pending/pos/java-override/B.scala b/tests/pos/java-override/B.scala similarity index 100% rename from tests/pending/pos/java-override/B.scala rename to tests/pos/java-override/B.scala From 20673f49bd218270e489e24ec030ceade91c2be8 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Fri, 23 Jan 2015 16:14:21 +0100 Subject: [PATCH 10/10] Handle AnnotatedTypes transparently like their underlying type In Erasure, all type annotations are dropped (AnnotatedTypes are replaced with their underlying). --- src/dotty/tools/dotc/TypeErasure.scala | 22 ++--- src/dotty/tools/dotc/ast/TreeInfo.scala | 2 +- src/dotty/tools/dotc/ast/TreeTypeMap.scala | 2 +- src/dotty/tools/dotc/ast/tpd.scala | 12 +-- src/dotty/tools/dotc/core/Denotations.scala | 2 +- .../tools/dotc/core/SymDenotations.scala | 9 +- .../tools/dotc/core/TypeApplications.scala | 16 ++-- src/dotty/tools/dotc/core/TypeComparer.scala | 20 +++-- src/dotty/tools/dotc/core/TypeOps.scala | 12 +-- src/dotty/tools/dotc/core/Types.scala | 85 +++++++++++-------- .../tools/dotc/transform/ElimByName.scala | 2 +- src/dotty/tools/dotc/transform/Erasure.scala | 21 +++-- .../tools/dotc/transform/ExplicitOuter.scala | 4 +- .../tools/dotc/transform/Literalize.scala | 6 +- src/dotty/tools/dotc/transform/Splitter.scala | 10 +-- .../tools/dotc/transform/SuperAccessors.scala | 9 +- src/dotty/tools/dotc/typer/Applications.scala | 26 +++--- src/dotty/tools/dotc/typer/Checking.scala | 10 +-- .../tools/dotc/typer/ErrorReporting.scala | 2 +- src/dotty/tools/dotc/typer/Implicits.scala | 14 +-- src/dotty/tools/dotc/typer/Inferencing.scala | 2 +- src/dotty/tools/dotc/typer/ProtoTypes.scala | 11 +-- src/dotty/tools/dotc/typer/TypeAssigner.scala | 19 +++-- src/dotty/tools/dotc/typer/Typer.scala | 16 ++-- 24 files changed, 182 insertions(+), 152 deletions(-) diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala index a45e29287f3d..807fd33f1a4b 100644 --- a/src/dotty/tools/dotc/TypeErasure.scala +++ b/src/dotty/tools/dotc/TypeErasure.scala @@ -38,7 +38,7 @@ object TypeErasure { case JavaArrayType(elem) => isErasedType(elem) case AnnotatedType(_, tp) => - isErasedType(tp) + false case ThisType(tref) => isErasedType(tref) case tp: MethodType => @@ -105,7 +105,7 @@ object TypeErasure { /** The erasure of a top-level reference. Differs from normal erasure in that * TermRefs are kept instead of being widened away. */ - def erasedRef(tp: Type)(implicit ctx: Context): Type = tp match { + def erasedRef(tp: Type)(implicit ctx: Context): Type = tp.stripAnnots match { case tp: TermRef => assert(tp.symbol.exists, tp) val tp1 = ctx.makePackageObjPrefixExplicit(tp) @@ -160,7 +160,7 @@ object TypeErasure { * as upper bound and that is not Java defined? Arrays of such types are * erased to `Object` instead of `ObjectArray`. */ - def isUnboundedGeneric(tp: Type)(implicit ctx: Context): Boolean = tp.dealias match { + def isUnboundedGeneric(tp: Type)(implicit ctx: Context): Boolean = tp.dealias.stripAnnots match { case tp: TypeRef => !tp.symbol.isClass && !tp.derivesFrom(defn.ObjectClass) && @@ -186,14 +186,14 @@ object TypeErasure { * come after S. * (the reason to pick last is that we prefer classes over traits that way). */ - def erasedLub(tp1: Type, tp2: Type)(implicit ctx: Context): Type = tp1 match { + def erasedLub(tp1: Type, tp2: Type)(implicit ctx: Context): Type = tp1.stripAnnots match { case JavaArrayType(elem1) => - tp2 match { + tp2.stripAnnots match { case JavaArrayType(elem2) => JavaArrayType(erasedLub(elem1, elem2)) case _ => defn.ObjectType } case _ => - tp2 match { + tp2.stripAnnots match { case JavaArrayType(_) => defn.ObjectType case _ => val cls2 = tp2.classSymbol @@ -216,14 +216,14 @@ object TypeErasure { * - subtypes over supertypes, unless isJava is set * - real classes over traits */ - def erasedGlb(tp1: Type, tp2: Type, isJava: Boolean)(implicit ctx: Context): Type = tp1 match { + def erasedGlb(tp1: Type, tp2: Type, isJava: Boolean)(implicit ctx: Context): Type = tp1.stripAnnots match { case JavaArrayType(elem1) => - tp2 match { + tp2.stripAnnots match { case JavaArrayType(elem2) => JavaArrayType(erasedGlb(elem1, elem2, isJava)) case _ => tp1 } case _ => - tp2 match { + tp2.stripAnnots match { case JavaArrayType(_) => tp2 case _ => val tsym1 = tp1.typeSymbol @@ -346,7 +346,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild else JavaArrayType(this(elemtp)) } - def eraseInfo(tp: Type, sym: Symbol)(implicit ctx: Context) = tp match { + def eraseInfo(tp: Type, sym: Symbol)(implicit ctx: Context) = tp.stripAnnots match { case ExprType(rt) => if (sym is Param) apply(tp) // Note that params with ExprTypes are eliminated by ElimByName, @@ -365,7 +365,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild (if (cls.owner is Package) normalizeClass(cls) else cls).typeRef } - private def eraseResult(tp: Type)(implicit ctx: Context): Type = tp match { + private def eraseResult(tp: Type)(implicit ctx: Context): Type = tp.stripAnnots match { case tp: TypeRef => val sym = tp.typeSymbol if (sym eq defn.UnitClass) sym.typeRef diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index 3d633c58d59a..5f851cd20c7d 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -359,7 +359,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => /** Is symbol potentially a getter of a mutable variable? */ def mayBeVarGetter(sym: Symbol)(implicit ctx: Context): Boolean = { - def maybeGetterType(tpe: Type): Boolean = tpe match { + def maybeGetterType(tpe: Type): Boolean = tpe.stripAnnots match { case _: ExprType | _: ImplicitMethodType => true case tpe: PolyType => maybeGetterType(tpe.resultType) case _ => false diff --git a/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/src/dotty/tools/dotc/ast/TreeTypeMap.scala index 846c661f5352..3dec85dfc1a9 100644 --- a/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -89,7 +89,7 @@ final class TreeTypeMap( case tree1 => tree1.withType(mapType(tree1.tpe)) match { case id: Ident if tpd.needsSelect(id.tpe) => - ref(id.tpe.asInstanceOf[TermRef]).withPos(id.pos) + ref(id.tpe.stripAnnots.asInstanceOf[TermRef]).withPos(id.pos) case ddef @ DefDef(name, tparams, vparamss, tpt, rhs) => val (tmap1, tparams1) = transformDefs(ddef.tparams) val (tmap2, vparamss1) = tmap1.transformVParamss(vparamss) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 77c607ca7606..a6d51d48d6e8 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -177,14 +177,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { polyDefDef(sym, Function.const(rhsFn)) def polyDefDef(sym: TermSymbol, rhsFn: List[Type] => List[List[Tree]] => Tree)(implicit ctx: Context): DefDef = { - val (tparams, mtp) = sym.info match { + val (tparams, mtp) = sym.info.stripAnnots match { case tp: PolyType => val tparams = ctx.newTypeParams(sym, tp.paramNames, EmptyFlags, tp.instantiateBounds) (tparams, tp.instantiate(tparams map (_.typeRef))) case tp => (Nil, tp) } - def valueParamss(tp: Type): (List[List[TermSymbol]], Type) = tp match { + def valueParamss(tp: Type): (List[List[TermSymbol]], Type) = tp.stripAnnots match { case tp @ MethodType(paramNames, paramTypes) => def valueParam(name: TermName, info: Type): TermSymbol = ctx.newSymbol(sym, name, TermParam, info) @@ -256,7 +256,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { // ------ Making references ------------------------------------------------------ def prefixIsElidable(tp: NamedType)(implicit ctx: Context) = { - def test(implicit ctx: Context) = tp.prefix match { + def test(implicit ctx: Context) = tp.prefix.stripAnnots match { case NoPrefix => true case pre: ThisType => @@ -273,7 +273,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } } - def needsSelect(tp: Type)(implicit ctx: Context) = tp match { + def needsSelect(tp: Type)(implicit ctx: Context) = tp.stripAnnots match { case tp: TermRef => !prefixIsElidable(tp) case _ => false } @@ -282,7 +282,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def ref(tp: NamedType)(implicit ctx: Context): Tree = if (tp.isType) TypeTree(tp) else if (prefixIsElidable(tp)) Ident(tp) - else tp.prefix match { + else tp.prefix.stripAnnots match { case pre: SingletonType => singleton(pre).select(tp) case pre => SelectFromTypeTree(TypeTree(pre), tp) } // no checks necessary @@ -290,7 +290,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def ref(sym: Symbol)(implicit ctx: Context): Tree = ref(NamedType(sym.owner.thisType, sym.name, sym.denot)) - def singleton(tp: Type)(implicit ctx: Context): Tree = tp match { + def singleton(tp: Type)(implicit ctx: Context): Tree = tp.stripAnnots match { case tp: TermRef => ref(tp) case tp: ThisType => This(tp.cls) case SuperType(qual, _) => singleton(qual) diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index cd585dea1cae..39f10dc21c3a 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -382,7 +382,7 @@ object Denotations { final def signature(implicit ctx: Context): Signature = { if (isType) Signature.NotAMethod // don't force info if this is a type SymDenotation - else info match { + else info.stripAnnots match { case info: MethodicType => try info.signature catch { // !!! DEBUG diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index c8fbb3d03977..ac66e2d9795a 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -510,7 +510,7 @@ object SymDenotations { /** Is `pre` the same as C.thisThis, where C is exactly the owner of this symbol, * or, if this symbol is protected, a subclass of the owner? */ - def isCorrectThisType(pre: Type): Boolean = pre match { + def isCorrectThisType(pre: Type): Boolean = pre.stripAnnots match { case pre: ThisType => (pre.cls eq owner) || (this is Protected) && pre.cls.derivesFrom(owner) case pre: TermRef => @@ -573,7 +573,7 @@ object SymDenotations { !( this.isTerm || this.isStaticOwner || ctx.erasedTypes - || (pre eq NoPrefix) || (pre eq thisType) + || (pre.stripAnnots eq NoPrefix) || (pre.stripAnnots eq thisType.stripAnnots) ) /** Is this symbol concrete, or that symbol deferred? */ @@ -617,7 +617,7 @@ object SymDenotations { /** The class implementing this module, NoSymbol if not applicable. */ final def moduleClass(implicit ctx: Context): Symbol = if (this is ModuleVal) - myInfo match { + myInfo.stripAnnots match { case info: TypeRef => info.symbol case ExprType(info: TypeRef) => info.symbol // needed after uncurry, when module terms might be accessor defs case info: LazyType => info.moduleClass @@ -626,7 +626,7 @@ object SymDenotations { else NoSymbol /** The module implemented by this module class, NoSymbol if not applicable. */ - final def sourceModule(implicit ctx: Context): Symbol = myInfo match { + final def sourceModule(implicit ctx: Context): Symbol = myInfo.stripAnnots match { case ClassInfo(_, _, _, _, selfType: TermRef) if this is ModuleClass => selfType.symbol case info: LazyType => @@ -1363,6 +1363,7 @@ object SymDenotations { case tp: TypeVar => tp.inst.exists && inCache(tp.inst) case tp: TypeProxy => inCache(tp.underlying) case tp: AndOrType => inCache(tp.tp1) && inCache(tp.tp2) + case tp: AnnotatedType => isCachable(tp.tpe) case _ => true } diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 7e23c7fff627..5ea656349443 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -250,9 +250,9 @@ class TypeApplications(val self: Type) extends AnyVal { */ final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = ctx.traceIndented(s"btwa ${self.show} wrt $base", core, show = true) { def default = self.baseTypeRef(base).appliedTo(baseArgInfos(base)) - self match { + self.stripAnnots match { case tp: TypeRef => - tp.info match { + tp.info.stripAnnots match { case TypeBounds(_, hi) => hi.baseTypeWithArgs(base) case _ => default } @@ -297,7 +297,7 @@ class TypeApplications(val self: Type) extends AnyVal { */ final def argInfos(interpolate: Boolean)(implicit ctx: Context): List[Type] = { var tparams: List[TypeSymbol] = null - def recur(tp: Type, refineCount: Int): mutable.ListBuffer[Type] = tp.stripTypeVar match { + def recur(tp: Type, refineCount: Int): mutable.ListBuffer[Type] = tp.stripTypeVar.stripAnnots match { case tp @ RefinedType(tycon, name) => val buf = recur(tycon, refineCount + 1) if (buf == null) null @@ -352,7 +352,7 @@ class TypeApplications(val self: Type) extends AnyVal { * * for a contravariant type-parameter becomes L. */ - final def argInfo(tparam: Symbol, interpolate: Boolean = true)(implicit ctx: Context): Type = self match { + final def argInfo(tparam: Symbol, interpolate: Boolean = true)(implicit ctx: Context): Type = self.stripAnnots match { case self: TypeAlias => self.alias case TypeBounds(lo, hi) => if (interpolate) { @@ -367,14 +367,14 @@ class TypeApplications(val self: Type) extends AnyVal { } /** The element type of a sequence or array */ - def elemType(implicit ctx: Context): Type = self match { + def elemType(implicit ctx: Context): Type = self.stripAnnots match { case defn.ArrayType(elemtp) => elemtp case JavaArrayType(elemtp) => elemtp case _ => firstBaseArgInfo(defn.SeqClass) } def containsSkolemType(target: Type)(implicit ctx: Context): Boolean = { - def recur(tp: Type): Boolean = tp.stripTypeVar match { + def recur(tp: Type): Boolean = tp.stripTypeVar.stripAnnots match { case SkolemType(tp) => tp eq target case tp: NamedType => @@ -434,7 +434,7 @@ class TypeApplications(val self: Type) extends AnyVal { for (sym <- boundSyms) yield TypeRef(SkolemType(rt), correspondingParamName(sym)) - def rewrite(tp: Type): Type = tp match { + def rewrite(tp: Type): Type = tp.stripAnnots match { case tp @ RefinedType(parent, name: TypeName) => if (correspondingNames contains name) rewrite(parent) else RefinedType( @@ -482,7 +482,7 @@ class TypeApplications(val self: Type) extends AnyVal { //println(i"lambda abstract $self wrt $boundSyms%, % --> $res") res } - self match { + self.stripAnnots match { case self @ TypeBounds(lo, hi) => self.derivedTypeBounds(lo, expand(TypeBounds.upper(hi))) case _ => diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index ce6787c1ea28..f9c7b11ab14d 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -200,7 +200,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi case tp2: LazyRef => isSubType(tp1, tp2.ref) case tp2: AnnotatedType => - isSubType(tp1, tp2.tpe) // todo: refine? + isSubType(tp1.stripAnnots, tp2.stripAnnots) // todo: refine? case tp2: ThisType => def compareThis = { val cls2 = tp2.cls @@ -282,7 +282,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi case tp1: LazyRef => isSubType(tp1.ref, tp2) case tp1: AnnotatedType => - isSubType(tp1.tpe, tp2) + isSubType(tp1.stripAnnots, tp2.stripAnnots) case OrType(tp11, tp12) => isSubType(tp11, tp2) && isSubType(tp12, tp2) case ErrorType => @@ -416,7 +416,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi } isSubType(hi1, tp2) || compareGADT case _ => - def isNullable(tp: Type): Boolean = tp.dealias match { + def isNullable(tp: Type): Boolean = tp.dealias.stripAnnots match { case tp: TypeRef => tp.symbol.isNullableClass case RefinedType(parent, _) => isNullable(parent) case AndType(tp1, tp2) => isNullable(tp1) && isNullable(tp2) @@ -453,7 +453,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi case JavaArrayType(elem2) => isSubType(elem1, elem2) case _ => tp2 isRef ObjectClass } - compareJavaArray + compareJavaArray + case tp1: AnnotatedType => + isSubType(tp1.stripAnnots, tp2.stripAnnots) case _ => false } @@ -599,7 +601,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi } /** Defer constraining type variables when compared against prototypes */ - def isMatchedByProto(proto: ProtoType, tp: Type) = tp.stripTypeVar match { + def isMatchedByProto(proto: ProtoType, tp: Type) = tp.stripTypeVar.stripAnnots match { case tp: PolyParam if constraint contains tp => true case _ => proto.isMatchedBy(tp) } @@ -644,9 +646,9 @@ 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, relaxed: Boolean): Boolean = tp1.widen match { + final def matchesType(tp1: Type, tp2: Type, relaxed: Boolean): Boolean = tp1.widen.stripAnnots match { case tp1: MethodType => - tp2.widen match { + tp2.widen.stripAnnots match { case tp2: MethodType => tp1.isImplicit == tp2.isImplicit && matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) && @@ -656,7 +658,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi matchesType(tp1.resultType, tp2, relaxed) } case tp1: PolyType => - tp2.widen match { + tp2.widen.stripAnnots match { case tp2: PolyType => sameLength(tp1.paramNames, tp2.paramNames) && matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed) @@ -664,7 +666,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi false } case _ => - tp2.widen match { + tp2.widen.stripAnnots match { case _: PolyType => false case tp2: MethodType => diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index 3e04eb037537..855c5bf833e3 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -18,7 +18,7 @@ trait TypeOps { this: Context => if ((pre eq NoType) || (pre eq NoPrefix) || (cls is PackageClass)) tp else if (thiscls.derivesFrom(cls) && pre.baseTypeRef(thiscls).exists) - pre match { + pre.stripAnnots match { case SuperType(thispre, _) => thispre case _ => pre } @@ -236,7 +236,7 @@ trait TypeOps { this: Context => case _ => tpe } - tpe.prefix match { + tpe.prefix.stripAnnots match { case pre: ThisType if pre.cls is Package => tryInsert(pre.cls) case pre: TermRef if pre.symbol is Package => tryInsert(pre.symbol.moduleClass) case _ => tpe @@ -255,7 +255,7 @@ trait TypeOps { this: Context => * unless a definition for `argSym` already exists in the current scope. */ def forwardRef(argSym: Symbol, from: Symbol, to: TypeBounds, cls: ClassSymbol, decls: Scope) = - argSym.info match { + argSym.info.stripAnnots match { case info @ TypeBounds(lo2 @ TypeRef(_: ThisType, name), hi2) => if (name == from.name && (lo2 eq hi2) && @@ -290,7 +290,7 @@ trait TypeOps { this: Context => * (2) X is not yet defined in current scope. This "short-circuiting" prevents * long chains of aliases which would have to be traversed in type comparers. */ - def forwardRefs(from: Symbol, to: Type, prefs: List[TypeRef]) = to match { + def forwardRefs(from: Symbol, to: Type, prefs: List[TypeRef]) = to.stripAnnots match { case to @ TypeBounds(lo1, hi1) if lo1 eq hi1 => for (pref <- prefs) for (argSym <- pref.decls) @@ -302,7 +302,7 @@ trait TypeOps { this: Context => // println(s"normalizing $parents of $cls in ${cls.owner}") // !!! DEBUG var refinements: SimpleMap[TypeName, Type] = SimpleMap.Empty var formals: SimpleMap[TypeName, Symbol] = SimpleMap.Empty - def normalizeToRef(tp: Type): TypeRef = tp match { + def normalizeToRef(tp: Type): TypeRef = tp.stripAnnots match { case tp @ RefinedType(tp1, name: TypeName) => val prevInfo = refinements(name) refinements = refinements.updated(name, @@ -357,7 +357,7 @@ trait TypeOps { this: Context => if (!(lo <:< hiBound)) violations += ((arg, "upper", hiBound)) if (!(bounds.lo <:< hi)) violations += ((arg, "lower", bounds.lo)) } - arg.tpe match { + arg.tpe.stripAnnots match { case TypeBounds(lo, hi) => checkOverlapsBounds(lo, hi) case tp => checkOverlapsBounds(tp, tp) } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 4e8bd5ed9671..398da4b32c49 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -94,6 +94,7 @@ object Types { case tp: TermRef => tp.termSymbol.isStable case _: SingletonType => true case NoPrefix => true + case tp: AnnotatedType => tp.tpe.isStable case _ => false } @@ -103,7 +104,7 @@ object Types { * It makes no sense for it to be an alias type because isRef would always * return false in that case. */ - def isRef(sym: Symbol)(implicit ctx: Context): Boolean = stripTypeVar match { + def isRef(sym: Symbol)(implicit ctx: Context): Boolean = stripTypeVar.stripAnnots match { case this1: TypeRef => this1.info match { // see comment in Namer#typeDefSig case TypeAlias(tp) => tp.isRef(sym) @@ -126,7 +127,7 @@ object Types { } /** Is this type an instance of a non-bottom subclass of the given class `cls`? */ - final def derivesFrom(cls: Symbol)(implicit ctx: Context): Boolean = this match { + final def derivesFrom(cls: Symbol)(implicit ctx: Context): Boolean = stripAnnots match { case tp: TypeRef => val sym = tp.symbol if (sym.isClass) sym.derivesFrom(cls) else tp.underlying.derivesFrom(cls) @@ -162,7 +163,7 @@ object Types { classSymbol is ModuleClass /** Is this type produced as a repair for an error? */ - final def isError(implicit ctx: Context): Boolean = stripTypeVar match { + final def isError(implicit ctx: Context): Boolean = stripTypeVar.stripAnnots match { case ErrorType => true case tp => (tp.typeSymbol is Erroneous) || (tp.termSymbol is Erroneous) } @@ -187,7 +188,7 @@ object Types { /** Is this the type of a method that has a repeated parameter type as * last parameter type? */ - def isVarArgsMethod(implicit ctx: Context): Boolean = this match { + def isVarArgsMethod(implicit ctx: Context): Boolean = stripAnnots match { case tp: PolyType => tp.resultType.isVarArgsMethod case MethodType(_, paramTypes) => paramTypes.nonEmpty && paramTypes.last.isRepeatedParam case _ => false @@ -202,7 +203,7 @@ object Types { * the same class are counted as equal for this purpose. */ def refines(prefix: Type)(implicit ctx: Context): Boolean = { - val prefix1 = prefix.dealias + val prefix1 = prefix.dealias.stripAnnots def loop(tp: Type): Boolean = (tp eq prefix1) || { tp match { @@ -246,13 +247,13 @@ object Types { new NamedPartsAccumulator(p).apply(mutable.LinkedHashSet(), this) /** Map function `f` over elements of an AndType, rebuilding with function `g` */ - def mapReduceAnd[T](f: Type => T)(g: (T, T) => T)(implicit ctx: Context): T = stripTypeVar match { + def mapReduceAnd[T](f: Type => T)(g: (T, T) => T)(implicit ctx: Context): T = stripTypeVar.stripAnnots match { case AndType(tp1, tp2) => g(tp1.mapReduceAnd(f)(g), tp2.mapReduceAnd(f)(g)) case _ => f(this) } /** Map function `f` over elements of an OrType, rebuilding with function `g` */ - final def mapReduceOr[T](f: Type => T)(g: (T, T) => T)(implicit ctx: Context): T = stripTypeVar match { + final def mapReduceOr[T](f: Type => T)(g: (T, T) => T)(implicit ctx: Context): T = stripTypeVar.stripAnnots match { case OrType(tp1, tp2) => g(tp1.mapReduceOr(f)(g), tp2.mapReduceOr(f)(g)) case _ => f(this) } @@ -414,7 +415,7 @@ object Types { case tp: TypeRef => tp.denot.findMember(name, pre, excluded) case tp: TermRef => - go (tp.underlying match { + go (tp.underlying.stripAnnots match { case mt: MethodType if mt.paramTypes.isEmpty && (tp.symbol is Stable) => mt.resultType case tp1 => tp1 @@ -582,7 +583,7 @@ object Types { * either type. */ final def overrides(that: Type)(implicit ctx: Context) = { - def result(tp: Type): Type = tp match { + def result(tp: Type): Type = tp.stripAnnots match { case ExprType(_) | MethodType(Nil, _) => tp.resultType case _ => tp } @@ -652,7 +653,7 @@ object Types { /** Remove all AnnotatedTypes wrapping this type. */ - def stripAnnots(implicit ctx: Context): Type = this + def stripAnnots: Type = this /** Widen from singleton type to its underlying non-singleton * base type by applying one or more `underlying` dereferences, @@ -665,6 +666,7 @@ object Types { */ final def widen(implicit ctx: Context): Type = widenSingleton match { case tp: ExprType => tp.resultType.widen + case tp: AnnotatedType => tp.derivedAnnotatedType(tp.annot, tp.tpe.widen) case tp => tp } @@ -673,6 +675,7 @@ object Types { */ final def widenSingleton(implicit ctx: Context): Type = stripTypeVar match { case tp: SingletonType if !tp.isOverloaded => tp.underlying.widenSingleton + case tp: AnnotatedType => tp.derivedAnnotatedType(tp.annot, tp.tpe.widenSingleton) case _ => this } @@ -681,6 +684,7 @@ object Types { */ final def widenExpr: Type = this match { case tp: ExprType => tp.resultType + case tp: AnnotatedType => tp.derivedAnnotatedType(tp.annot, tp.tpe.widenExpr) case _ => this } @@ -688,6 +692,7 @@ object Types { final def widenIfUnstable(implicit ctx: Context): Type = stripTypeVar match { case tp: ExprType => tp.resultType.widenIfUnstable case tp: TermRef if !tp.symbol.isStable => tp.underlying.widenIfUnstable + case tp: AnnotatedType => tp.derivedAnnotatedType(tp.annot, tp.tpe.widenIfUnstable) case _ => this } @@ -696,7 +701,7 @@ object Types { */ final def dealias(implicit ctx: Context): Type = this match { case tp: TypeRef => - tp.info match { + tp.info.stripAnnots match { case TypeAlias(tp) => tp.dealias case _ => tp } @@ -721,6 +726,7 @@ object Types { */ final def deconst(implicit ctx: Context): Type = stripTypeVar match { case tp: ConstantType => tp.value.tpe + case tp: AnnotatedType => tp.derivedAnnotatedType(tp.annot, tp.tpe.deconst) case _ => this } @@ -729,6 +735,7 @@ object Types { */ final def unrefine(implicit ctx: Context): Type = stripTypeVar match { case tp @ RefinedType(tycon, _) => tycon.unrefine + case tp: AnnotatedType => tp.derivedAnnotatedType(tp.annot, tp.tpe.unrefine) case _ => this } @@ -736,12 +743,11 @@ object Types { * a class, the class type ref, otherwise NoType. * @param refinementOK If `true` we also skip non-parameter refinements. */ - def underlyingClassRef(refinementOK: Boolean)(implicit ctx: Context): Type = dealias match { + def underlyingClassRef(refinementOK: Boolean)(implicit ctx: Context): Type = dealias.stripAnnots match { case tp: TypeRef => if (tp.symbol.isClass) tp else if (tp.symbol.isAliasType) tp.underlying.underlyingClassRef(refinementOK) else NoType - case tp: AnnotatedType => tp.underlying.underlyingClassRef(refinementOK) case tp: RefinedType => if (refinementOK) tp.underlying.underlyingClassRef(refinementOK) else { @@ -783,7 +789,7 @@ object Types { * yields `String` as the result of lookupRefined. */ def lookupRefined(name: Name)(implicit ctx: Context): Type = { - def loop(pre: Type): Type = pre.stripTypeVar match { + def loop(pre: Type): Type = pre.stripTypeVar.stripAnnots match { case pre: RefinedType => if (pre.refinedName ne name) loop(pre.parent) else pre.refinedInfo match { @@ -858,21 +864,21 @@ object Types { } /** The parameter types of a PolyType or MethodType, Empty list for others */ - final def paramTypess: List[List[Type]] = this match { + final def paramTypess: List[List[Type]] = stripAnnots match { case mt: MethodType => mt.paramTypes :: mt.resultType.paramTypess case pt: PolyType => pt.resultType.paramTypess case _ => Nil } /** The parameter types in the first parameter section of a PolyType or MethodType, Empty list for others */ - final def firstParamTypes: List[Type] = this match { + final def firstParamTypes: List[Type] = stripAnnots match { case mt: MethodType => mt.paramTypes case pt: PolyType => pt.resultType.firstParamTypes case _ => Nil } /** Is this either not a method at all, or a parameterless method? */ - final def isParameterless: Boolean = this match { + final def isParameterless: Boolean = stripAnnots match { case mt: MethodType => false case pt: PolyType => pt.resultType.isParameterless case _ => true @@ -884,14 +890,14 @@ object Types { /** The final result type of a PolyType, MethodType, or ExprType, after skipping * all parameter sections, the type itself for all others. */ - def finalResultType: Type = resultType match { + def finalResultType: Type = resultType.stripAnnots match { case mt: MethodType => mt.resultType.finalResultType case pt: PolyType => pt.resultType.finalResultType case _ => resultType } /** This type seen as a TypeBounds */ - final def bounds(implicit ctx: Context): TypeBounds = this match { + final def bounds(implicit ctx: Context): TypeBounds = stripAnnots match { case tp: TypeBounds => tp case ci: ClassInfo => TypeAlias(ci.typeRef) case wc: WildcardType => @@ -1917,7 +1923,7 @@ object Types { protected def computeSignature(implicit ctx: Context): Signature - protected def resultSignature(implicit ctx: Context) = try resultType match { + protected def resultSignature(implicit ctx: Context) = try resultType.stripAnnots match { case rtp: MethodicType => rtp.signature case tp => Signature(tp, isJava = false) } @@ -1959,7 +1965,7 @@ object Types { tp match { case MethodParam(`thisMethodType`, _) => true case tp @ TypeRef(MethodParam(`thisMethodType`, _), name) => - tp.info match { // follow type arguments to avoid dependency + tp.info.stripAnnots match { // follow type arguments to avoid dependency case TypeAlias(tp)=> apply(x, tp) case _ => true } @@ -2035,13 +2041,18 @@ object Types { def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType = apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType) def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = { - def paramInfo(param: Symbol): Type = param.info match { - case AnnotatedType(annot, tp) if annot matches defn.RepeatedAnnot => - val typeSym = param.info.typeSymbol.asClass - assert(typeSym == defn.SeqClass || typeSym == defn.ArrayClass) - tp.translateParameterized(typeSym, defn.RepeatedParamClass) - case tp => - tp + def paramInfo(param: Symbol): Type = { + def recur(info: Type): Type = info match { + case AnnotatedType(annot, tp) if annot matches defn.RepeatedAnnot => + val typeSym = param.info.typeSymbol.asClass + assert(typeSym == defn.SeqClass || typeSym == defn.ArrayClass) + tp.translateParameterized(typeSym, defn.RepeatedParamClass) + case tp: AnnotatedType => + tp.derivedAnnotatedType(tp.annot, recur(tp.tpe)) + case tp => + tp + } + recur(param.info) } def transformResult(mt: MethodType) = resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _))) @@ -2176,7 +2187,7 @@ object Types { * - fromBelow and param <:< bound * - !fromBelow and param >:> bound */ - def occursIn(bound: Type, fromBelow: Boolean)(implicit ctx: Context): Boolean = bound.stripTypeVar match { + def occursIn(bound: Type, fromBelow: Boolean)(implicit ctx: Context): Boolean = bound.stripTypeVar.stripAnnots match { case bound: PolyParam => bound == this case bound: AndOrType => def occ1 = occursIn(bound.tp1, fromBelow) @@ -2268,7 +2279,7 @@ object Types { */ def instantiate(fromBelow: Boolean)(implicit ctx: Context): Type = { def upperBound = ctx.typerState.constraint.fullUpperBound(origin) - def isSingleton(tp: Type): Boolean = tp match { + def isSingleton(tp: Type): Boolean = tp.stripAnnots match { case tp: SingletonType => true case AndType(tp1, tp2) => isSingleton(tp1) | isSingleton(tp2) case OrType(tp1, tp2) => isSingleton(tp1) & isSingleton(tp2) @@ -2280,7 +2291,7 @@ object Types { case tp: AndOrType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2) case _ => true } - def isOrType(tp: Type): Boolean = tp.stripTypeVar.dealias match { + def isOrType(tp: Type): Boolean = tp.stripTypeVar.dealias.stripAnnots match { case tp: OrType => true case AndType(tp1, tp2) => isOrType(tp1) | isOrType(tp2) case RefinedType(parent, _) => isOrType(parent) @@ -2467,7 +2478,7 @@ object Types { case _ => this } - def contains(tp: Type)(implicit ctx: Context) = tp match { + def contains(tp: Type)(implicit ctx: Context) = tp.stripAnnots match { case tp: TypeBounds => lo <:< tp.lo && tp.hi <:< hi case _ => lo <:< tp && tp <:< hi } @@ -2561,8 +2572,10 @@ object Types { if ((annot eq this.annot) && (tpe eq this.tpe)) this else AnnotatedType(annot, tpe) - override def stripTypeVar(implicit ctx: Context): Type = tpe.stripTypeVar - override def stripAnnots(implicit ctx: Context): Type = tpe.stripAnnots + override def stripTypeVar(implicit ctx: Context): Type = derivedAnnotatedType(annot, tpe.stripTypeVar) + override def stripAnnots: Type = tpe.stripAnnots + override def resultType: Type = tpe.resultType + override def signature(implicit ctx: Context): Signature = tpe.signature } object AnnotatedType { @@ -2626,7 +2639,7 @@ object Types { * denotation of the single abstract method as a member of the type. */ object SAMType { - def zeroParamClass(tp: Type)(implicit ctx: Context): Type = tp match { + def zeroParamClass(tp: Type)(implicit ctx: Context): Type = tp.stripAnnots match { case tp: ClassInfo => def zeroParams(tp: Type): Boolean = tp match { case pt: PolyType => zeroParams(pt.resultType) @@ -2660,7 +2673,7 @@ object Types { val absMems = tp.abstractTermMembers // println(s"absMems: ${absMems map (_.show) mkString ", "}") if (absMems.size == 1) - absMems.head.info match { + absMems.head.info.stripAnnots match { case mt: MethodType if !mt.isDependent => Some(absMems.head) case _ => None } diff --git a/src/dotty/tools/dotc/transform/ElimByName.scala b/src/dotty/tools/dotc/transform/ElimByName.scala index ca84fcaec9ad..3eea5feda3bb 100644 --- a/src/dotty/tools/dotc/transform/ElimByName.scala +++ b/src/dotty/tools/dotc/transform/ElimByName.scala @@ -85,7 +85,7 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform arg } - val MethodType(_, formals) = tree.fun.tpe.widen + val MethodType(_, formals) = tree.fun.tpe.widen.stripAnnots val args1 = tree.args.zipWithConserve(formals)(transformArg) cpy.Apply(tree)(tree.fun, args1) } diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index 933252ccd2d4..33c41fcff3a6 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -214,7 +214,7 @@ object Erasure extends TypeTestsCasts{ */ def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree = if (pt.isInstanceOf[FunProto]) tree - else tree.tpe.widen match { + else tree.tpe.widen.stripAnnots match { case MethodType(Nil, _) if tree.isTerm => adaptToType(tree.appliedToNone, pt) case tpw => @@ -236,9 +236,9 @@ object Erasure extends TypeTestsCasts{ class Typer extends typer.ReTyper with NoChecking { import Boxing._ - def erasedType(tree: untpd.Tree)(implicit ctx: Context): Type = tree.typeOpt match { + def erasedType(tree: untpd.Tree)(implicit ctx: Context): Type = tree.typeOpt.stripAnnots match { case tp: TermRef if tree.isTerm => erasedRef(tp) - case tp => erasure(tp) + case _ => erasure(tree.typeOpt) } override def promote(tree: untpd.Tree)(implicit ctx: Context): tree.ThisTree[Type] = { @@ -306,18 +306,18 @@ object Erasure extends TypeTestsCasts{ } def recur(qual: Tree): Tree = { - val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType + val qualIsPrimitive = qual.tpe.widen.stripAnnots.isPrimitiveValueType val symIsPrimitive = sym.owner.isPrimitiveValueClass if ((sym.owner eq defn.AnyClass) || (sym.owner eq defn.AnyValClass)) { assert(sym.isConstructor, s"${sym.showLocated}") select(qual, defn.ObjectClass.info.decl(sym.name).symbol) } - else if (qualIsPrimitive && !symIsPrimitive || qual.tpe.isErasedValueType) + else if (qualIsPrimitive && !symIsPrimitive || qual.tpe.stripAnnots.isErasedValueType) recur(box(qual)) else if (!qualIsPrimitive && symIsPrimitive) recur(unbox(qual, sym.owner.typeRef)) else if (sym.owner eq defn.ArrayClass) - selectArrayMember(qual, erasure(tree.qualifier.typeOpt.widen.finalResultType)) + selectArrayMember(qual, erasure(tree.qualifier.typeOpt.widen.finalResultType.stripAnnots)) else { val qual1 = adaptIfSuper(qual) if (qual1.tpe.derivesFrom(sym.owner) || qual1.isInstanceOf[Super]) @@ -376,7 +376,7 @@ object Erasure extends TypeTestsCasts{ case fun1: Apply => // arguments passed in prototype were already passed fun1 case fun1 => - fun1.tpe.widen match { + fun1.tpe.widen.stripAnnots match { case mt: MethodType => val outers = outer.args(fun.asInstanceOf[tpd.Tree]) // can't use fun1 here because its type is already erased val args1 = (outers ::: args ++ protoArgs(pt)).zipWithConserve(mt.paramTypes)(typedExpr) @@ -500,7 +500,12 @@ object Erasure extends TypeTestsCasts{ }) } - override def adapt(tree: Tree, pt: Type, original: untpd.Tree)(implicit ctx: Context): Tree = + override def adapt(tree: Tree, pt: Type, original: untpd.Tree)(implicit ctx: Context): Tree = { + val tree1 = adapt1(tree, pt, original) + tree1.withType(tree1.tpe.stripAnnots) + } + + def adapt1(tree: Tree, pt: Type, original: untpd.Tree)(implicit ctx: Context): Tree = ctx.traceIndented(i"adapting ${tree.showSummary}: ${tree.tpe} to $pt", show = true) { assert(ctx.phase == ctx.erasurePhase.next, ctx.phase) if (tree.isEmpty) tree diff --git a/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/src/dotty/tools/dotc/transform/ExplicitOuter.scala index ba74de0a36ac..1d0c88e0977b 100644 --- a/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -50,6 +50,8 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf val newDecls = decls.cloneScope newOuterAccessors(cls).foreach(newDecls.enter) tp.derivedClassInfo(decls = newDecls) + case tp: AnnotatedType => + tp.derivedAnnotatedType(tp.annot, transformInfo(tp.tpe, sym)) case _ => tp } @@ -201,7 +203,7 @@ object ExplicitOuter { case thisTree @ This(_) => isOuter(thisTree.symbol) case id: Ident => - id.tpe match { + id.tpe.stripAnnots match { case ref @ TermRef(NoPrefix, _) => ref.symbol.is(Method) && isOuter(id.symbol.owner.enclosingClass) // methods will be placed in enclosing class scope by LambdaLift, so they will get diff --git a/src/dotty/tools/dotc/transform/Literalize.scala b/src/dotty/tools/dotc/transform/Literalize.scala index c5b6f1c21aa5..e451f67586a7 100644 --- a/src/dotty/tools/dotc/transform/Literalize.scala +++ b/src/dotty/tools/dotc/transform/Literalize.scala @@ -51,7 +51,7 @@ class Literalize extends MiniPhaseTransform { thisTransform => * Revisit this issue once we have implemented `inline`. Then we can demand * purity of the prefix unless the selection goes to an inline val. */ - def literalize(tree: Tree)(implicit ctx: Context): Tree = tree.tpe match { + def literalize(tree: Tree)(implicit ctx: Context): Tree = tree.tpe.stripAnnots match { case ConstantType(value) if isIdempotentExpr(tree) => Literal(value) case _ => tree } @@ -68,7 +68,7 @@ class Literalize extends MiniPhaseTransform { thisTransform => override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree = literalize(tree) - override def transformLiteral(tree: Literal)(implicit ctx: Context, info: TransformerInfo): Tree = tree.tpe match { + override def transformLiteral(tree: Literal)(implicit ctx: Context, info: TransformerInfo): Tree = tree.tpe.stripAnnots match { case ConstantType(const) if tree.const.value != const.value || (tree.const.tag != const.tag) => Literal(const) case _ => tree } @@ -78,7 +78,7 @@ class Literalize extends MiniPhaseTransform { thisTransform => override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = { tree match { case Literal(c @ Constant(treeValue)) => - tree.tpe match { + tree.tpe.stripAnnots match { case ConstantType(c2 @ Constant(typeValue)) => assert(treeValue == typeValue && c2.tag == c.tag, i"Type of Literal $tree is inconsistent with underlying constant") diff --git a/src/dotty/tools/dotc/transform/Splitter.scala b/src/dotty/tools/dotc/transform/Splitter.scala index 0a1e1b238aaf..2af3635abad9 100644 --- a/src/dotty/tools/dotc/transform/Splitter.scala +++ b/src/dotty/tools/dotc/transform/Splitter.scala @@ -18,7 +18,7 @@ class Splitter extends MiniPhaseTransform { thisTransform => override def phaseName: String = "splitter" /** Replace self referencing idents with ThisTypes. */ - override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = tree.tpe match { + override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = tree.tpe.stripAnnots match { case tp: ThisType => ctx.debuglog(s"owner = ${ctx.owner}, context = ${ctx}") This(tp.cls) withPos tree.pos @@ -45,7 +45,7 @@ class Splitter extends MiniPhaseTransform { thisTransform => def memberDenot(tp: Type): SingleDenotation = { val mbr = tp.member(name) if (!mbr.isOverloaded) mbr.asSingleDenotation - else tree.tpe match { + else tree.tpe.stripAnnots match { case tref: TermRefWithSignature => mbr.atSignature(tref.sig) case _ => ctx.error(s"cannot disambiguate overloaded member $mbr"); NoDenotation } @@ -54,9 +54,9 @@ class Splitter extends MiniPhaseTransform { thisTransform => def candidates(tp: Type): List[Symbol] = { val mbr = memberDenot(tp) if (mbr.symbol.exists) mbr.symbol :: Nil - else tp.widen match { + else tp.widen.stripAnnots match { case tref: TypeRef => - tref.info match { + tref.info.stripAnnots match { case TypeBounds(_, hi) => candidates(hi) case _ => Nil } @@ -69,7 +69,7 @@ class Splitter extends MiniPhaseTransform { thisTransform => } } - def isStructuralSelect(tp: Type): Boolean = tp.stripTypeVar match { + def isStructuralSelect(tp: Type): Boolean = tp.stripTypeVar.stripAnnots match { case tp: RefinedType => tp.refinedName == name || isStructuralSelect(tp.parent) case tp: TypeProxy => isStructuralSelect(tp.underlying) case AndType(tp1, tp2) => isStructuralSelect(tp1) || isStructuralSelect(tp2) diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index f727201b2895..e58b167c5a9d 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -76,8 +76,9 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this buf += tree } - private def ensureMethodic(tpe: Type)(implicit ctx: Context) = tpe match { + private def ensureMethodic(tpe: Type)(implicit ctx: Context): Type = tpe match { case tpe: MethodicType => tpe + case tpe: AnnotatedType => tpe.derivedAnnotatedType(tpe.annot, ensureMethodic(tpe.tpe)) case _ => ExprType(tpe) } @@ -250,7 +251,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this def forwardParamAccessors(stats: List[Tree]): List[Tree] = { val (superArgs, superParamNames) = impl.parents match { case superCall @ Apply(fn, args) :: _ => - fn.tpe.widen match { + fn.tpe.widen.stripAnnots match { case MethodType(paramNames, _) => (args, paramNames) case _ => (Nil, Nil) } @@ -391,7 +392,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this transformAssign case Apply(fn, args) => - val MethodType(_, formals) = fn.tpe.widen + val MethodType(_, formals) = fn.tpe.widen.stripAnnots ctx.atPhase(thisTransformer.next) { implicit ctx => cpy.Apply(tree)(transform(fn), transformArgs(formals, args)) } @@ -434,7 +435,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this // has to take an object of exactly this type, otherwise it's more general val receiverType = if (isThisType(sym.info.finalResultType)) clazz.thisType else clazz.classInfo.selfType val accType = { - def accTypeOf(tpe: Type): Type = tpe match { + def accTypeOf(tpe: Type): Type = tpe.stripAnnots match { case tpe: PolyType => tpe.derivedPolyType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType)) case _ => diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index c012e8837718..a276c2b59bc5 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -68,7 +68,7 @@ object Applications { if (seqArg.exists) return args map Function.const(seqArg) } else return getUnapplySelectors(getTp, args, pos) - else if (defn.isProductSubType(unapplyResult)) return productSelectorTypes(unapplyResult, pos) + else if (defn.isProductSubType(unapplyResult)) return productSelectorTypes(unapplyResult, pos).map(_.stripAnnots) } if (unapplyResult derivesFrom defn.SeqClass) seqSelector :: Nil else if (unapplyResult isRef defn.BooleanClass) Nil @@ -153,7 +153,7 @@ trait Applications extends Compatibility { self: Typer => /** The function's type after widening and instantiating polytypes * with polyparams in constraint set */ - val methType = funType.widen match { + val methType = funType.widen.stripAnnots match { case funType: MethodType => funType case funType: PolyType => constrained(funType).resultType case tp => tp //was: funType @@ -168,7 +168,7 @@ trait Applications extends Compatibility { self: Typer => else args - protected def init() = methType match { + protected def init() = methType.stripAnnots match { case methType: MethodType => // apply the result type constraint, unless method type is dependent if (!methType.isDependent) { @@ -254,7 +254,7 @@ trait Applications extends Compatibility { self: Typer => val meth = methRef.symbol.asTerm val receiver: Tree = methPart(normalizedFun) match { case Select(receiver, _) => receiver - case mr => mr.tpe.normalizedPrefix match { + case mr => mr.tpe.normalizedPrefix.stripAnnots match { case mr: TermRef => ref(mr) case _ => EmptyTree } @@ -523,7 +523,7 @@ trait Applications extends Compatibility { self: Typer => // a modified tree but this would be more convoluted and less efficient. if (proto.isTupled) proto = proto.tupled - methPart(fun1).tpe match { + methPart(fun1).tpe.stripAnnots match { case funRef: TermRef => tryEither { implicit ctx => val app = @@ -540,7 +540,7 @@ trait Applications extends Compatibility { self: Typer => cpy.Apply(tree)(untpd.TypedSplice(fun2), proto.typedArgs map untpd.TypedSplice), pt) } case _ => - fun1.tpe match { + fun1.tpe.stripAnnots match { case ErrorType => tree.withType(ErrorType) case tp => handleUnexpectedFunType(tree, fun1) } @@ -585,7 +585,7 @@ trait Applications extends Compatibility { self: Typer => def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = track("typedTypeApply") { var typedArgs = tree.args mapconserve (typedType(_)) val typedFn = typedExpr(tree.fun, PolyProto(typedArgs.tpes, pt)) - typedFn.tpe.widen match { + typedFn.tpe.widen.stripAnnots match { case pt: PolyType => def adaptTypeArg(tree: tpd.Tree, bound: Type): tpd.Tree = if (bound.isLambda && !tree.tpe.isLambda && tree.tpe.typeParams.nonEmpty) @@ -622,8 +622,8 @@ trait Applications extends Compatibility { self: Typer => tree match { case tree: untpd.RefTree => val ttree = typedType(untpd.rename(tree, tree.name.toTypeName)) - ttree.tpe match { - case alias: TypeRef if alias.info.isAlias => + ttree.tpe.stripAnnots match { + case alias: TypeRef if alias.info.stripAnnots.isAlias => companionRef(alias) match { case companion: TermRef => return untpd.ref(companion) withPos tree.pos case _ => @@ -682,19 +682,19 @@ trait Applications extends Compatibility { self: Typer => */ def isSubTypeOfParent(subtp: Type, tp: Type)(implicit ctx: Context): Boolean = if (subtp <:< tp) true - else tp match { + else tp.stripAnnots match { case RefinedType(parent, _) => isSubTypeOfParent(subtp, parent) case _ => false } - unapplyFn.tpe.widen match { + unapplyFn.tpe.widen.stripAnnots match { case mt: MethodType if mt.paramTypes.length == 1 && !mt.isDependent => val m = mt val unapplyArgType = mt.paramTypes.head unapp.println(i"unapp arg tpe = $unapplyArgType, pt = $selType") def wpt = widenForMatchSelector(selType) // needed? val ownType = - if (selType <:< unapplyArgType) { + if (selType.stripAnnots <:< unapplyArgType) { //fullyDefinedType(unapplyArgType, "extractor argument", tree.pos) unapp.println(i"case 1 $unapplyArgType ${ctx.typerState.constraint}") selType @@ -853,7 +853,7 @@ trait Applications extends Compatibility { self: Typer => }} /** Drop any implicit parameter section */ - def stripImplicit(tp: Type): Type = tp match { + def stripImplicit(tp: Type): Type = tp.stripAnnots match { case mt: ImplicitMethodType if !mt.isDependent => mt.resultType // todo: make sure implicit method types are not dependent case pt: PolyType => diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index 1354b8926183..b8460da85e02 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -62,7 +62,7 @@ object Checking { /** Check info `tp` for cycles. Throw CyclicReference for illegal cycles, * break direct cycle with a LazyRef for legal, F-bounded cycles. */ - def checkInfo(tp: Type): Type = tp match { + def checkInfo(tp: Type): Type = tp.stripAnnots match { case tp @ TypeAlias(alias) => try tp.derivedTypeAlias(apply(alias)) finally { @@ -102,7 +102,7 @@ object Checking { // to symbol `sym` itself. We only check references with interesting // prefixes for cycles. This pruning is done in order not to force // global symbols when doing the cyclicity check. - def isInteresting(prefix: Type): Boolean = prefix.stripTypeVar match { + def isInteresting(prefix: Type): Boolean = prefix.stripTypeVar.stripAnnots match { case NoPrefix => true case prefix: ThisType => sym.owner.isClass && prefix.cls.isContainedIn(sym.owner) case prefix: NamedType => !prefix.symbol.isStaticOwner && isInteresting(prefix.prefix) @@ -246,7 +246,7 @@ trait Checking { * @return `tp` itself if it is a class or trait ref, ObjectClass.typeRef if not. */ def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type = - tp.underlyingClassRef(refinementOK = false) match { + tp.underlyingClassRef(refinementOK = false).stripAnnots match { case tref: TypeRef => if (ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos) if (traitReq && !(tref.symbol is Trait)) ctx.error(d"$tref is not a trait", pos) @@ -270,7 +270,7 @@ trait Checking { * their lower bound conforms to their upper cound. If a type argument is * infeasible, issue and error and continue with upper bound. */ - def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp match { + def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp.stripAnnots match { case tp: RefinedType => tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where)) case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => @@ -310,7 +310,7 @@ trait Checking { } cls.info.decls.foreach(checkDecl) - cls.info match { + cls.info.stripAnnots match { case ClassInfo(_, _, _, _, selfSym: Symbol) => checkDecl(selfSym) case _ => } diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala index 2ed720f83444..cddc5e7e60a4 100644 --- a/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -86,7 +86,7 @@ object ErrorReporting { else if (denot.symbol.exists) denot.symbol.showLocated else anonymousTypeMemberStr(denot.info) - def refStr(tp: Type): String = tp match { + def refStr(tp: Type): String = tp.stripAnnots match { case tp: NamedType => denotStr(tp.denot) case _ => anonymousTypeMemberStr(tp) } diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 24d9ebf6d8b7..6042af253f7a 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -46,13 +46,13 @@ object Implicits { def refMatches(ref: TermRef)(implicit ctx: Context) = { - def discardForView(tpw: Type, argType: Type): Boolean = tpw match { + def discardForView(tpw: Type, argType: Type): Boolean = tpw.stripAnnots match { case mt: MethodType => mt.isImplicit || mt.paramTypes.length != 1 || !(argType <:< mt.paramTypes.head)(ctx.fresh.setExploreTyperState) case poly: PolyType => - poly.resultType match { + poly.resultType.stripAnnots match { case mt: MethodType => mt.isImplicit || mt.paramTypes.length != 1 || @@ -68,13 +68,13 @@ object Implicits { !tpw.derivesFrom(defn.FunctionClass(1)) || tpw.isRef(defn.PredefConformsClass) } - def discardForValueType(tpw: Type): Boolean = tpw match { + def discardForValueType(tpw: Type): Boolean = tpw.stripAnnots match { case mt: MethodType => !mt.isImplicit case mt: PolyType => discardForValueType(tpw.resultType) case _ => false } - def discard = pt match { + def discard = pt.stripAnnots match { case pt: ViewProto => discardForView(ref.widen, pt.argType) case _: ValueTypeOrProto => !defn.isFunctionType(pt) && discardForValueType(ref.widen) case _ => false @@ -302,7 +302,7 @@ trait ImplicitRunInfo { self: RunInfo => def collectCompanions(tp: Type): TermRefSet = track("computeImplicicScope") { ctx.traceIndented(i"collectCompanions($tp)", implicits) { val comps = new TermRefSet - tp match { + tp.stripAnnots match { case tp: NamedType => val pre = tp.prefix comps ++= iscopeRefs(pre) @@ -377,9 +377,9 @@ trait Implicits { self: Typer => !from.isError && !to.isError && (ctx.mode is Mode.ImplicitsEnabled) - && { from.widenExpr match { + && { from.widenExpr.stripAnnots match { case from: TypeRef if defn.ScalaValueClasses contains from.symbol => - to.widenExpr match { + to.widenExpr.stripAnnots match { case to: TypeRef if defn.ScalaValueClasses contains to.symbol => util.Stats.record("isValueSubClass") return defn.isValueSubClass(from.symbol, to.symbol) diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index e41b2d194274..16055314bcf4 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -107,7 +107,7 @@ trait Inferencing { this: Checking => * that companion module. Otherwise NoType */ def companionRef(tp: Type)(implicit ctx: Context): Type = - tp.underlyingClassRef(refinementOK = true) match { + tp.underlyingClassRef(refinementOK = true).stripAnnots match { case tp: TypeRef => val companion = tp.classSymbol.companionModule if (companion.exists) diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index 521f0deaae0e..a782d4496f36 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -45,16 +45,16 @@ object ProtoTypes { /** Check that the result type of the current method * fits the given expected result type. */ - def constrainResult(mt: Type, pt: Type)(implicit ctx: Context): Boolean = pt match { + def constrainResult(mt: Type, pt: Type)(implicit ctx: Context): Boolean = pt.stripAnnots match { case _: FunProto => - mt match { + mt.stripAnnots match { case mt: MethodType => mt.isDependent || constrainResult(mt.resultType, pt.resultType) case _ => true } case _: ValueTypeOrProto if !(pt isRef defn.UnitClass) => - mt match { + mt.stripAnnots match { case mt: MethodType => mt.isDependent || isCompatible(normalize(mt, pt), pt) case _ => @@ -138,7 +138,7 @@ object ProtoTypes { */ def selectionProto(name: Name, tp: Type, typer: Typer)(implicit ctx: Context) = if (name.isConstructorName) WildcardType - else tp match { + else tp.stripAnnots match { case tp: UnapplyFunProto => new UnapplySelectionProto(name) case tp => SelectionProto(name, IgnoredProto(tp), typer) } @@ -276,7 +276,7 @@ object ProtoTypes { */ case class PolyProto(targs: List[Type], override val resultType: Type) extends UncachedGroundType with ProtoType { override def isMatchedBy(tp: Type)(implicit ctx: Context) = { - def isInstantiatable(tp: Type) = tp.widen match { + def isInstantiatable(tp: Type) = tp.widen.stripAnnots match { case PolyType(paramNames) => paramNames.length == targs.length case _ => false } @@ -361,6 +361,7 @@ object ProtoTypes { } } case et: ExprType => et.resultType + case tp: AnnotatedType => tp.derivedAnnotatedType(tp.annot, normalize(tp.tpe, pt)) case _ => tp } } diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 46aa2e953bd6..90ad5ed7ea4c 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -31,7 +31,7 @@ trait TypeAssigner { def avoid(tp: Type, syms: => List[Symbol])(implicit ctx: Context): Type = { val widenMap = new TypeMap { lazy val forbidden = syms.toSet - def toAvoid(tp: Type): Boolean = tp match { + def toAvoid(tp: Type): Boolean = tp.stripAnnots match { case tp: TermRef => val sym = tp.symbol sym.exists && ( @@ -112,9 +112,9 @@ trait TypeAssigner { * that the package object shows up as the prefix. */ def ensureAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = { - def test(tpe: Type, firstTry: Boolean): Type = tpe match { + def test(tpe: Type, firstTry: Boolean): Type = tpe.stripAnnots match { case tpe: NamedType => - val pre = tpe.prefix + val pre = tpe.prefix.stripAnnots val name = tpe.name val d = tpe.denot.accessibleFrom(pre, superAccess) if (!d.exists) { @@ -183,7 +183,7 @@ trait TypeAssigner { tree.withType(tp) def assignType(tree: untpd.Select, qual: Tree)(implicit ctx: Context): Select = { - def qualType = qual.tpe.widen + def qualType = qual.tpe.widen.stripAnnots def arrayElemType = { val JavaArrayType(elemtp) = qualType elemtp @@ -222,7 +222,7 @@ trait TypeAssigner { def assignType(tree: untpd.Super, qual: Tree, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context) = { val mix = tree.mix - val qtype @ ThisType(_) = qual.tpe + val qtype @ ThisType(_) = qual.tpe.stripAnnots val cls = qtype.cls def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match { @@ -245,25 +245,30 @@ trait TypeAssigner { } def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = { - val ownType = fn.tpe.widen match { + def recur(tp: Type): Type = tp.widen match { case fntpe @ MethodType(_, ptypes) => if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes) else errorType(i"wrong number of parameters for ${fn.tpe}; expected: ${ptypes.length}", tree.pos) + case tp: AnnotatedType => + tp.derivedAnnotatedType(tp.annot, recur(tp.tpe)) case t => errorType(i"${err.exprStr(fn)} does not take parameters", tree.pos) } + val ownType = recur(fn.tpe) tree.withType(ownType) } def assignType(tree: untpd.TypeApply, fn: Tree, args: List[Tree])(implicit ctx: Context) = { - val ownType = fn.tpe.widen match { + def recur(tp: Type): Type = tp match { case pt: PolyType => val argTypes = args.tpes if (sameLength(argTypes, pt.paramNames)|| ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes) else errorType(d"wrong number of type parameters for ${fn.tpe}; expected: ${pt.paramNames.length}", tree.pos) + case tp: AnnotatedType => tp.derivedAnnotatedType(tp.annot, recur(tp.tpe)) case _ => errorType(i"${err.exprStr(fn)} does not take type parameters", tree.pos) } + val ownType = recur(fn.tpe.widen) tree.withType(ownType) } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 683d457d08a3..69d78d397c51 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -271,7 +271,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit ErrorType } - val tree1 = ownType match { + val tree1 = ownType.stripAnnots match { case ownType: NamedType if !prefixIsElidable(ownType) => ref(ownType).withPos(tree.pos) case _ => @@ -413,14 +413,14 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def canAssign(sym: Symbol) = // allow assignments from the primary constructor to class fields sym.is(Mutable, butNot = Accessor) || ctx.owner.isPrimaryConstructor && !sym.is(Method) && sym.owner == ctx.owner.owner - lhsCore.tpe match { + lhsCore.tpe.stripAnnots match { case ref: TermRef if canAssign(ref.symbol) => assignType(cpy.Assign(tree)(lhs1, typed(tree.rhs, ref.info))) case _ => def reassignmentToVal = errorTree(cpy.Assign(tree)(lhsCore, typed(tree.rhs, lhs1.tpe.widen)), "reassignment to val") - lhsCore.tpe match { + lhsCore.tpe.stripAnnots match { case ref: TermRef => // todo: further conditions to impose on getter? val pre = ref.prefix val setterName = ref.name.setterName @@ -549,7 +549,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit */ def inferredParamType(param: untpd.ValDef, formal: Type): Type = { if (isFullyDefined(formal, ForceDegree.noBottom)) return formal - calleeType.widen match { + calleeType.widen.stripAnnots match { case mtpe: MethodType => val pos = params indexWhere (_.name == param.name) if (pos < mtpe.paramTypes.length) { @@ -1244,7 +1244,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } - def adaptToArgs(wtp: Type, pt: FunProto): Tree = wtp match { + def adaptToArgs(wtp: Type, pt: FunProto): Tree = wtp.stripAnnots match { case _: MethodType | _: PolyType => def isUnary = wtp.firstParamTypes match { case ptype :: Nil => !ptype.isRepeatedParam @@ -1263,7 +1263,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } - def adaptNoArgs(wtp: Type): Tree = wtp match { + def adaptNoArgs(wtp: Type): Tree = wtp.stripAnnots match { case wtp: ExprType => adaptInterpolated(tree.withType(wtp.resultType), pt, original) case wtp: ImplicitMethodType if constrainResult(wtp, pt) => @@ -1326,7 +1326,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit tree match { case Closure(Nil, id @ Ident(nme.ANON_FUN), _) if defn.isFunctionType(wtp) && !defn.isFunctionType(pt) => - pt match { + pt.stripAnnots match { case SAMType(meth) if wtp <:< meth.info.toFunctionType() => // was ... && isFullyDefined(pt, ForceDegree.noBottom) @@ -1350,7 +1350,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit tree match { case _: MemberDef | _: PackageDef | _: Import | _: WithoutTypeOrPos[_] => tree - case _ => tree.tpe.widen match { + case _ => tree.tpe.widen.stripAnnots match { case ErrorType => tree case ref: TermRef =>