Skip to content

Commit 9641b2a

Browse files
committed
Merge pull request #339 from dotty-staging/fix/#329-and-others
Fix/#329 and others
2 parents 329b6bf + 976ed6f commit 9641b2a

30 files changed

+146
-108
lines changed

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
759759
Ident(defn.ScalaRuntimeModule.requiredMethod(name).termRef).appliedToArgs(args)
760760
}
761761

762+
/** An extractor that pulls out type arguments */
763+
object MaybePoly {
764+
def unapply(tree: Tree): Option[(Tree, List[Tree])] = tree match {
765+
case TypeApply(tree, targs) => Some(tree, targs)
766+
case _ => Some(tree, Nil)
767+
}
768+
}
769+
762770
/** A traverser that passes the enlcosing class or method as an argumenr
763771
* to the traverse method.
764772
*/

src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ class TypeApplications(val self: Type) extends AnyVal {
285285
*/
286286
def underlyingIfRepeated(isJava: Boolean)(implicit ctx: Context): Type =
287287
if (self.isRepeatedParam) {
288-
val seqClass = if(isJava) defn.ArrayClass else defn.SeqClass
288+
val seqClass = if (isJava) defn.ArrayClass else defn.SeqClass
289289
translateParameterized(defn.RepeatedParamClass, seqClass)
290290
}
291291
else self

src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -648,45 +648,34 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
648648
// Tests around `matches`
649649

650650
/** A function implementing `tp1` matches `tp2`. */
651-
final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = tp1 match {
651+
final def matchesType(tp1: Type, tp2: Type, relaxed: Boolean): Boolean = tp1.widen match {
652652
case tp1: MethodType =>
653-
tp2 match {
653+
tp2.widen match {
654654
case tp2: MethodType =>
655655
tp1.isImplicit == tp2.isImplicit &&
656656
matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) &&
657-
matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), alwaysMatchSimple)
658-
case tp2: ExprType =>
659-
tp1.paramNames.isEmpty &&
660-
matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
661-
case _ =>
662-
false
663-
}
664-
case tp1: ExprType =>
665-
tp2 match {
666-
case tp2: MethodType =>
667-
tp2.paramNames.isEmpty &&
668-
matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
669-
case tp2: ExprType =>
670-
matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
671-
case _ =>
672-
false // was: matchesType(tp1.resultType, tp2, alwaysMatchSimple)
657+
matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed)
658+
case tp2 =>
659+
relaxed && tp1.paramNames.isEmpty &&
660+
matchesType(tp1.resultType, tp2, relaxed)
673661
}
674662
case tp1: PolyType =>
675-
tp2 match {
663+
tp2.widen match {
676664
case tp2: PolyType =>
677665
sameLength(tp1.paramNames, tp2.paramNames) &&
678-
matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), alwaysMatchSimple)
666+
matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed)
679667
case _ =>
680668
false
681669
}
682670
case _ =>
683-
tp2 match {
684-
case _: MethodType | _: PolyType =>
671+
tp2.widen match {
672+
case _: PolyType =>
685673
false
686-
case tp2: ExprType =>
687-
false // was: matchesType(tp1, tp2.resultType, alwaysMatchSimple)
688-
case _ =>
689-
alwaysMatchSimple || isSameType(tp1, tp2)
674+
case tp2: MethodType =>
675+
relaxed && tp2.paramNames.isEmpty &&
676+
matchesType(tp1, tp2.resultType, relaxed)
677+
case tp2 =>
678+
relaxed || isSameType(tp1, tp2)
690679
}
691680
}
692681

src/dotty/tools/dotc/core/Types.scala

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -598,17 +598,21 @@ object Types {
598598
* - Either both types are polytypes with the same number of
599599
* type parameters and their result types match after renaming
600600
* corresponding type parameters
601-
* - Or both types are (possibly nullary) method types with equivalent parameter types
602-
* and matching result types
603-
* - Or both types are equivalent
604-
* - Or phase.erasedTypes is false and both types are neither method nor
605-
* poly types.
601+
* - Or both types are method types with =:=-equivalent(*) parameter types
602+
* and matching result types after renaming corresponding parameter types
603+
* if the method types are dependent.
604+
* - Or both types are =:=-equivalent
605+
* - Or phase.erasedTypes is false, and neither type takes
606+
* term or type parameters.
607+
*
608+
* (*) when matching with a Java method, we also regard Any and Object as equivalent
609+
* parameter types.
606610
*/
607611
def matches(that: Type)(implicit ctx: Context): Boolean =
608612
if (Config.newMatch) this.signature matches that.signature
609613
else track("matches") {
610614
ctx.typeComparer.matchesType(
611-
this, that, alwaysMatchSimple = !ctx.phase.erasedTypes)
615+
this, that, relaxed = !ctx.phase.erasedTypes)
612616
}
613617

614618
/** This is the same as `matches` except that it also matches => T with T and

src/dotty/tools/dotc/transform/OverridingPairs.scala

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,7 @@ object OverridingPairs {
3939
* relative to <base>.this do
4040
*/
4141
protected def matches(sym1: Symbol, sym2: Symbol): Boolean =
42-
sym1.isType || {
43-
val info1 = self.memberInfo(sym1)
44-
val info2 = self.memberInfo(sym2)
45-
// info1.signature == info2.signature && // TODO enable for speed
46-
info1 matches info2
47-
}
42+
sym1.isType || self.memberInfo(sym1).matches(self.memberInfo(sym2))
4843

4944
/** The symbols that can take part in an overriding pair */
5045
private val decls = {

src/dotty/tools/dotc/typer/EtaExpansion.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ object EtaExpansion {
3434
* lhs += expr
3535
*/
3636
def liftAssigned(defs: mutable.ListBuffer[Tree], tree: Tree)(implicit ctx: Context): Tree = tree match {
37-
case Apply(fn @ Select(pre, name), args) =>
38-
cpy.Apply(tree)(cpy.Select(fn)(lift(defs, pre), name), liftArgs(defs, fn.tpe, args))
37+
case Apply(MaybePoly(fn @ Select(pre, name), targs), args) =>
38+
cpy.Apply(tree)(
39+
cpy.Select(fn)(
40+
lift(defs, pre), name).appliedToTypeTrees(targs),
41+
liftArgs(defs, fn.tpe, args))
3942
case Select(pre, name) =>
4043
cpy.Select(tree)(lift(defs, pre), name)
4144
case _ =>

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -400,10 +400,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
400400
tree.lhs match {
401401
case lhs @ Apply(fn, args) =>
402402
typed(cpy.Apply(lhs)(untpd.Select(fn, nme.update), args :+ tree.rhs), pt)
403-
case untpd.TypedSplice(Apply(Select(fn, app), args)) if app == nme.apply =>
404-
typed(cpy.Apply(fn)(
405-
untpd.Select(untpd.TypedSplice(fn), nme.update),
406-
(args map untpd.TypedSplice) :+ tree.rhs), pt)
403+
case untpd.TypedSplice(Apply(MaybePoly(Select(fn, app), targs), args)) if app == nme.apply =>
404+
val rawUpdate: untpd.Tree = untpd.Select(untpd.TypedSplice(fn), nme.update)
405+
val wrappedUpdate =
406+
if (targs.isEmpty) rawUpdate
407+
else untpd.TypeApply(rawUpdate, targs map untpd.TypedSplice)
408+
val appliedUpdate = cpy.Apply(fn)(wrappedUpdate, (args map untpd.TypedSplice) :+ tree.rhs)
409+
typed(appliedUpdate, pt)
407410
case lhs =>
408411
val lhsCore = typedUnadapted(lhs)
409412
def lhs1 = typed(untpd.TypedSplice(lhsCore))

test/dotc/tests.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ class tests extends CompilerTest {
8282
@Test def neg_autoTupling = compileFile(posDir, "autoTuplingTest", "-language:noAutoTupling" :: Nil, xerrors = 4)
8383
@Test def neg_autoTupling2 = compileFile(negDir, "autoTuplingTest", xerrors = 4)
8484
@Test def neg_companions = compileFile(negDir, "companions", xerrors = 1)
85-
@Test def neg_over = compileFile(negDir, "over", xerrors = 1)
86-
@Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 7)
85+
@Test def neg_over = compileFile(negDir, "over", xerrors = 3)
86+
@Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 11)
8787
@Test def neg_projections = compileFile(negDir, "projections", xerrors = 1)
8888
@Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1)
8989
@Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4)

tests/pending/pos/t3363-new.scala renamed to tests/disabled/structural-type/pos/t3363-new.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ object TestCase {
77

88
//if fs was reduced to List (generic type with one parameter) then the code compiles
99
//if you inherit from MapOps[T] instead of MapOps[F] then code compiles fine
10-
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] {
10+
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] {
1111
//if you remove this line, then code compiles
1212
lazy val m: TypeTag[T] = sys.error("just something to make it compile")
1313
def is(xs: List[T]) = List(xs)

tests/pending/pos/t3363-old.scala renamed to tests/disabled/structural-type/pos/t3363-old.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ object TestCase {
55

66
//if fs was reduced to List (generic type with one parameter) then the code compiles
77
//if you inherit from MapOps[T] instead of MapOps[F] then code compiles fine
8-
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] {
8+
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] {
99
//if you remove this line, then code compiles
1010
lazy val m: Manifest[T] = sys.error("just something to make it compile")
1111
def is(xs: List[T]) = List(xs)

tests/neg/over.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,11 @@ class C extends T {
88
override val y = 2
99

1010
}
11+
12+
class D extends T {
13+
14+
def x(): String = ""
15+
16+
}
17+
18+

tests/neg/overrides.scala

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,45 @@ class Y2 extends X2 {
7979
class X3 {
8080
override type T = A1
8181
}
82+
83+
package p3 {
84+
85+
// Dotty change of rules: Toverrider#f does not
86+
// override TCommon#f, hence the accidental override rule
87+
// applies.
88+
trait TCommon {
89+
def f: String
90+
}
91+
92+
class C1 extends TCommon {
93+
def f = "in C1"
94+
}
95+
96+
trait TOverrider { this: TCommon =>
97+
override def f = "in TOverrider" // The overridden self-type member...
98+
}
99+
100+
class C2 extends C1 with TOverrider // ... fails to override, here.
101+
102+
}
103+
104+
package p4 {
105+
106+
abstract class C[T] { def head: T }
107+
case class D[T](head: Int) extends C[T]
108+
109+
}
110+
111+
package p5 {
112+
class A {
113+
def m: String = "foo"
114+
}
115+
116+
class B extends A {
117+
override val m: Int = 42
118+
}
119+
120+
class C extends A {
121+
override def m: Int = 42
122+
}
123+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public interface A {
2+
void o(Object o);
3+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//trait T { def t(o: Object): Unit }
2+
3+
class B extends A /*with T*/ {
4+
override def o(o: Any): Unit = ()
5+
6+
//override def t(o: AnyRef): Unit = ()
7+
}

tests/pending/pos/self-type-override.scala

Lines changed: 0 additions & 13 deletions
This file was deleted.

tests/pending/pos/t3278.scala

Lines changed: 0 additions & 15 deletions
This file was deleted.

tests/pending/pos/t3480.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
object Test {
2-
val List(_*) = List(1)
2+
val List(_: _*) = List(1)
33
val Array( who, what : _* ) = "Eclipse plugin cannot not handle this" split (" ")
44
}
File renamed without changes.

tests/pending/pos/scoping1.scala renamed to tests/pos/scoping1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ object This extends App {
22
trait A {
33
def foo(): Unit
44
}
5-
class C { self: A =>
5+
abstract class C { self: A =>
66
def bar() = this.foo()
77
}
88
class D extends C with A {
File renamed without changes.
File renamed without changes.

tests/pos/subtyping.scala

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,5 @@
1-
class A {
2-
def test1(): Unit = {
3-
implicitly[this.type <:< this.type]
4-
implicitly[this.type <:< A]
5-
}
6-
}
71
object test {
82

9-
def tag1[T](x: T): String & T = ???
10-
def tag2[T](x: T): T & String = ???
11-
12-
val x1: Int & String = tag1(0)
13-
val x2: Int & String = tag2(0)
14-
val x3: String & Int = tag1(0)
15-
val x4: String & Int = tag2(0)
16-
17-
}
18-
19-
object test2 {
20-
21-
class A
22-
class B
23-
24-
val x: A | B = ???
25-
val y: B | A = x
26-
27-
val a: A & B = ???
28-
val b: B & A = a
3+
val x: Int = 1
294

305
}
31-
32-

tests/pending/pos/t319.scala renamed to tests/pos/t319.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ object test {
1414
val a = new A { type T = String };
1515
/** val b: B { type T = String } = functor(a) */
1616
val b: B { type T = String } = {
17-
val tmp = new functor() { val arg = a };
17+
val tmp = new functor() { val arg: A { type T = String } = a };
18+
// Dotty deviaton: arg needs an explicit type here, or else the inherited type `A` would be assumed.
1819
tmp.res
1920
}
2021

File renamed without changes.

tests/pos/t3278.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class Foo
2+
class Test {
3+
def update[B](x : B, b : Int): Unit = {}
4+
def apply[B](x : B) = 1
5+
}
6+
class Test2 {
7+
type B = Foo
8+
def update(x : B, b : Int): Unit = {}
9+
def apply(x : B) = 1
10+
}
11+
12+
object Test {
13+
def main(a : Array[String]): Unit = {
14+
val a = new Test
15+
val f = new Foo
16+
a(f) = 1 //works
17+
a(f) = a(f) + 1 //works
18+
a(f) += 1 //error: reassignment to val
19+
}
20+
}
21+
object Test2 {
22+
def main(args : Array[String]): Unit = {
23+
args(0) += "a"
24+
val a = new Test2
25+
val f = new Foo
26+
a(f) = 1 //works
27+
a(f) = a(f) + 1 //works
28+
a(f) += 1 //error: reassignment to val
29+
}
30+
}
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)