Skip to content

Fix/#329 and others #339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Feb 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 15 additions & 26 deletions src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -648,45 +648,34 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
// Tests around `matches`

/** A function implementing `tp1` matches `tp2`. */
final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = tp1 match {
final def matchesType(tp1: Type, tp2: Type, relaxed: Boolean): Boolean = tp1.widen match {
case tp1: MethodType =>
tp2 match {
tp2.widen match {
case tp2: MethodType =>
tp1.isImplicit == tp2.isImplicit &&
matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) &&
matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), alwaysMatchSimple)
case tp2: ExprType =>
tp1.paramNames.isEmpty &&
matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
case _ =>
false
}
case tp1: ExprType =>
tp2 match {
case tp2: MethodType =>
tp2.paramNames.isEmpty &&
matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
case tp2: ExprType =>
matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
case _ =>
false // was: matchesType(tp1.resultType, tp2, alwaysMatchSimple)
matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed)
case tp2 =>
relaxed && tp1.paramNames.isEmpty &&
matchesType(tp1.resultType, tp2, relaxed)
}
case tp1: PolyType =>
tp2 match {
tp2.widen match {
case tp2: PolyType =>
sameLength(tp1.paramNames, tp2.paramNames) &&
matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), alwaysMatchSimple)
matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed)
case _ =>
false
}
case _ =>
tp2 match {
case _: MethodType | _: PolyType =>
tp2.widen match {
case _: PolyType =>
false
case tp2: ExprType =>
false // was: matchesType(tp1, tp2.resultType, alwaysMatchSimple)
case _ =>
alwaysMatchSimple || isSameType(tp1, tp2)
case tp2: MethodType =>
relaxed && tp2.paramNames.isEmpty &&
matchesType(tp1, tp2.resultType, relaxed)
case tp2 =>
relaxed || isSameType(tp1, tp2)
}
}

Expand Down
16 changes: 10 additions & 6 deletions src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -598,17 +598,21 @@ object Types {
* - Either both types are polytypes with the same number of
* type parameters and their result types match after renaming
* corresponding type parameters
* - Or both types are (possibly nullary) method types with equivalent parameter types
* and matching result types
* - Or both types are equivalent
* - Or phase.erasedTypes is false and both types are neither method nor
* poly types.
* - Or both types are method types with =:=-equivalent(*) parameter types
* and matching result types after renaming corresponding parameter types
* if the method types are dependent.
* - Or both types are =:=-equivalent
* - Or phase.erasedTypes is false, and neither type takes
* term or type parameters.
*
* (*) when matching with a Java method, we also regard Any and Object as equivalent
* parameter types.
*/
def matches(that: Type)(implicit ctx: Context): Boolean =
if (Config.newMatch) this.signature matches that.signature
else track("matches") {
ctx.typeComparer.matchesType(
this, that, alwaysMatchSimple = !ctx.phase.erasedTypes)
this, that, relaxed = !ctx.phase.erasedTypes)
}

/** This is the same as `matches` except that it also matches => T with T and
Expand Down
7 changes: 1 addition & 6 deletions src/dotty/tools/dotc/transform/OverridingPairs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ object OverridingPairs {
* relative to <base>.this do
*/
protected def matches(sym1: Symbol, sym2: Symbol): Boolean =
sym1.isType || {
val info1 = self.memberInfo(sym1)
val info2 = self.memberInfo(sym2)
// info1.signature == info2.signature && // TODO enable for speed
info1 matches info2
}
sym1.isType || self.memberInfo(sym1).matches(self.memberInfo(sym2))

/** The symbols that can take part in an overriding pair */
private val decls = {
Expand Down
7 changes: 5 additions & 2 deletions src/dotty/tools/dotc/typer/EtaExpansion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 _ =>
Expand Down
11 changes: 7 additions & 4 deletions src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
4 changes: 2 additions & 2 deletions test/dotc/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ class tests extends CompilerTest {
@Test def neg_autoTupling = compileFile(posDir, "autoTuplingTest", "-language:noAutoTupling" :: Nil, xerrors = 4)
@Test def neg_autoTupling2 = compileFile(negDir, "autoTuplingTest", xerrors = 4)
@Test def neg_companions = compileFile(negDir, "companions", xerrors = 1)
@Test def neg_over = compileFile(negDir, "over", xerrors = 1)
@Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 7)
@Test def neg_over = compileFile(negDir, "over", xerrors = 3)
@Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 11)
@Test def neg_projections = compileFile(negDir, "projections", xerrors = 1)
@Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1)
@Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions tests/neg/over.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@ class C extends T {
override val y = 2

}

class D extends T {

def x(): String = ""

}


42 changes: 42 additions & 0 deletions tests/neg/overrides.scala
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,45 @@ class Y2 extends X2 {
class X3 {
override type T = A1
}

package p3 {

// Dotty change of rules: Toverrider#f does not
// override TCommon#f, hence the accidental override rule
// applies.
trait TCommon {
def f: String
}

class C1 extends TCommon {
def f = "in C1"
}

trait TOverrider { this: TCommon =>
override def f = "in TOverrider" // The overridden self-type member...
}

class C2 extends C1 with TOverrider // ... fails to override, here.

}

package p4 {

abstract class C[T] { def head: T }
case class D[T](head: Int) extends C[T]

}

package p5 {
class A {
def m: String = "foo"
}

class B extends A {
override val m: Int = 42
}

class C extends A {
override def m: Int = 42
}
}
3 changes: 3 additions & 0 deletions tests/pending/pos/java-override/A.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public interface A {
void o(Object o);
}
7 changes: 7 additions & 0 deletions tests/pending/pos/java-override/B.scala
Original file line number Diff line number Diff line change
@@ -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 = ()
}
13 changes: 0 additions & 13 deletions tests/pending/pos/self-type-override.scala

This file was deleted.

15 changes: 0 additions & 15 deletions tests/pending/pos/t3278.scala

This file was deleted.

2 changes: 1 addition & 1 deletion tests/pending/pos/t3480.scala
Original file line number Diff line number Diff line change
@@ -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 (" ")
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
File renamed without changes.
File renamed without changes.
29 changes: 1 addition & 28 deletions tests/pos/subtyping.scala
Original file line number Diff line number Diff line change
@@ -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

}


3 changes: 2 additions & 1 deletion tests/pending/pos/t319.scala → tests/pos/t319.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
File renamed without changes.
30 changes: 30 additions & 0 deletions tests/pos/t3278.scala
Original file line number Diff line number Diff line change
@@ -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
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.