aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-02-12 11:28:35 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2015-03-18 11:09:43 +0100
commit61cb51acaedbe603add8c4af9e390a27f8b33f09 (patch)
tree2e6f7d2410b96b208b3f6be5c5465a320751d7f0
parent3f5d15defa7481da1b9d1f20e91569a340c71e8e (diff)
downloaddotty-61cb51acaedbe603add8c4af9e390a27f8b33f09.tar.gz
dotty-61cb51acaedbe603add8c4af9e390a27f8b33f09.tar.bz2
dotty-61cb51acaedbe603add8c4af9e390a27f8b33f09.zip
Disallow refinements of types or methods that do not appear in parent.
We planned this for a long time but never implemented it. Instead, we sometimes issued an erro in Splitter, namely if reflection would have been needed to access the member. It turns out that some tests (e.g. neg/t625) fail -Ycheck (we knew that before and disabled) but also fail Pickling because they generate orhpan PolyParams. So rather than patching this up it seems now is a good time to enforce the restriction for real.
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala4
-rw-r--r--test/dotc/tests.scala17
-rw-r--r--tests/neg/structural.scala70
-rw-r--r--tests/neg/t0586.scala9
-rw-r--r--tests/neg/t0625.scala8
-rw-r--r--tests/neg/t1131.scala4
-rw-r--r--tests/neg/typers.scala4
-rw-r--r--tests/pos/i262-null-subtyping.scala11
-rw-r--r--tests/pos/structural.scala21
-rw-r--r--tests/pos/t1053.scala3
-rw-r--r--tests/pos/t2810.scala8
-rw-r--r--tests/pos/typers.scala1
-rw-r--r--tests/pos/zoo.scala27
13 files changed, 98 insertions, 89 deletions
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 5dc0452d1..331657e12 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -801,6 +801,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
typr.println(s"adding refinement $refinement")
checkRefinementNonCyclic(refinement, refineCls, seen)
val rsym = refinement.symbol
+ if ((rsym.is(Method) || rsym.isType) && rsym.allOverriddenSymbols.isEmpty) {
+ println(refineCls.baseClasses)
+ ctx.error(i"refinement $rsym without matching type in parent $parent", refinement.pos)
+ }
val rinfo = if (rsym is Accessor) rsym.info.resultType else rsym.info
RefinedType(parent, rsym.name, rt => rinfo.substThis(refineCls, SkolemType(rt)))
// todo later: check that refinement is within bounds
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 3babe7bc6..1a9d19913 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -56,7 +56,6 @@ class tests extends CompilerTest {
@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")
@Test def pos_approximateUnion = compileFile(posDir, "approximateUnion")
@Test def pos_tailcall = compileDir(posDir + "tailcall/")
@@ -87,16 +86,10 @@ class tests extends CompilerTest {
@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)
+ @Test def neg_i39 = compileFile(negDir, "i39", xerrors = 2)
+ @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 6)
@Test def neg_t0273_doubledefs = compileFile(negDir, "t0273", xerrors = 1)
- @Test def neg_t0586_structural = compileFile(negDir, "t0586", xerrors = 1)
- @Test def neg_t0625_structural = compileFile(negDir, "t0625", xerrors = 1)(
- defaultOptions = noCheckOptions)
- // -Ycheck fails because there are structural types involving higher-kinded types.
- // these are illegal, but are tested only later.
- @Test def neg_t1131_structural = compileFile(negDir, "t1131", xerrors = 1)
- @Test def neg_zoo = compileFile(negDir, "zoo", xerrors = 1)
+ @Test def neg_zoo = compileFile(negDir, "zoo", xerrors = 12)
@Test def neg_t1192_legalPrefix = compileFile(negDir, "t1192", xerrors = 1)
@Test def neg_tailcall_t1672b = compileFile(negDir, "tailcall/t1672b", xerrors = 6)
@Test def neg_tailcall_t3275 = compileFile(negDir, "tailcall/t3275", xerrors = 1)
@@ -108,13 +101,13 @@ class tests extends CompilerTest {
@Test def neg_t1843_variances = compileFile(negDir, "t1843-variances", xerrors = 1)
@Test def neg_t2660_ambi = compileFile(negDir, "t2660", xerrors = 2)
@Test def neg_t2994 = compileFile(negDir, "t2994", xerrors = 2)
- @Test def neg_subtyping = compileFile(negDir, "subtyping", xerrors = 2)
+ @Test def neg_subtyping = compileFile(negDir, "subtyping", xerrors = 4)
@Test def neg_variances = compileFile(negDir, "variances", xerrors = 2)
@Test def neg_badAuxConstr = compileFile(negDir, "badAuxConstr", xerrors = 2)
@Test def neg_typetest = compileFile(negDir, "typetest", xerrors = 1)
@Test def neg_t1569_failedAvoid = compileFile(negDir, "t1569-failedAvoid", xerrors = 1)
@Test def neg_cycles = compileFile(negDir, "cycles", xerrors = 8)
- @Test def neg_boundspropagation = compileFile(negDir, "boundspropagation", xerrors = 4)
+ @Test def neg_boundspropagation = compileFile(negDir, "boundspropagation", xerrors = 5)
@Test def neg_refinedSubtyping = compileFile(negDir, "refinedSubtyping", xerrors = 2)
@Test def neg_i0091_infpaths = compileFile(negDir, "i0091-infpaths", xerrors = 3)
@Test def neg_i0248_inherit_refined = compileFile(negDir, "i0248-inherit-refined", xerrors = 4)
diff --git a/tests/neg/structural.scala b/tests/neg/structural.scala
new file mode 100644
index 000000000..1d2506290
--- /dev/null
+++ b/tests/neg/structural.scala
@@ -0,0 +1,70 @@
+package p1 {
+
+object test123 {
+ type A = { def a: Int }
+ def f(a: A): A = a
+}
+
+object structural2 {
+ type A = { def a: Int }
+
+ type B = {
+ def b: Int
+ }
+
+ type AB = A & B
+
+ def f(ab: AB): AB = ab
+
+ f(new {
+ def a = 43
+ def b = 42
+ })
+}
+}
+
+package p2 {
+object RClose {
+ type ReflectCloseable = { def close(): Unit }
+ def withReflectCloseable[T <: ReflectCloseable, R](s: T)(action: T => R): R =
+ try {
+ action(s)
+ } finally {
+ s.close()
+ }
+}
+}
+
+package p3 {
+object Test {
+ def idMap[C[_],T](m: { def map[U](f: T => U): C[U] }): C[T] = m.map(t => t)
+
+ def main(args: Array[String]): Unit = {
+ idMap(Some(5))
+ idMap(Responder.constant(5))
+ }
+}
+}
+package p4 {
+
+trait A { self: Any { def p: Any } =>
+ def f(b: => Unit): Unit = {}
+ f { p } // error: cannot access member 'p' from structural type
+}
+}
+
+package p5 {
+// t2810
+object Test {
+ val closeable1: { def close(): Unit } = new scala.io.Source { val iter: Iterator[Char] = "".iterator }
+ val closeable2: { def close(): Unit } = new java.io.Closeable { def close() = {} }
+}
+}
+
+package p6 {
+
+ class Refinements {
+ val y: C { val x: T; type T } // was adeprecated warning: illegal forward reference in refinement; now illegal
+ }
+
+}
diff --git a/tests/neg/t0586.scala b/tests/neg/t0586.scala
deleted file mode 100644
index 540e225a1..000000000
--- a/tests/neg/t0586.scala
+++ /dev/null
@@ -1,9 +0,0 @@
-object RClose {
- type ReflectCloseable = { def close(): Unit }
- def withReflectCloseable[T <: ReflectCloseable, R](s: T)(action: T => R): R =
- try {
- action(s)
- } finally {
- s.close()
- }
-}
diff --git a/tests/neg/t0625.scala b/tests/neg/t0625.scala
deleted file mode 100644
index 561454259..000000000
--- a/tests/neg/t0625.scala
+++ /dev/null
@@ -1,8 +0,0 @@
-object Test {
- def idMap[C[_],T](m: { def map[U](f: T => U): C[U] }): C[T] = m.map(t => t)
-
- def main(args: Array[String]): Unit = {
- idMap(Some(5))
- idMap(Responder.constant(5))
- }
-}
diff --git a/tests/neg/t1131.scala b/tests/neg/t1131.scala
deleted file mode 100644
index f4a7b377d..000000000
--- a/tests/neg/t1131.scala
+++ /dev/null
@@ -1,4 +0,0 @@
-trait A { self: Any { def p: Any } =>
- def f(b: => Unit): Unit = {}
- f { p } // error: cannot access member 'p' from structural type
-}
diff --git a/tests/neg/typers.scala b/tests/neg/typers.scala
index 226fd2310..b5bd1fa2c 100644
--- a/tests/neg/typers.scala
+++ b/tests/neg/typers.scala
@@ -60,8 +60,4 @@ object typers {
123
}
}
-
- class Refinements {
- val y: C { val x: T; type T } // deprecated warning: illegal forward reference in refinement
- }
}
diff --git a/tests/pos/i262-null-subtyping.scala b/tests/pos/i262-null-subtyping.scala
index 284be49e8..5e57fcca0 100644
--- a/tests/pos/i262-null-subtyping.scala
+++ b/tests/pos/i262-null-subtyping.scala
@@ -1,12 +1,9 @@
object O {
- // This compiles
- val a: { type T } = null;
- val b: Any { type T } = null;
+ trait Base extends Any { type T }
+ val a: Base { type T } = null;
+ val b: Any with Base { type T } = null;
- // This doesn't:
- // found : Null
- // required: AnyRef{T}
- val c: AnyRef { type T } = null;
+ val c: AnyRef with Base { type T } = null;
class A
class B
diff --git a/tests/pos/structural.scala b/tests/pos/structural.scala
deleted file mode 100644
index 8afa49ed0..000000000
--- a/tests/pos/structural.scala
+++ /dev/null
@@ -1,21 +0,0 @@
-object test123 {
- type A = { def a: Int }
- def f(a: A): A = a
-}
-
-object structural2 {
- type A = { def a: Int }
-
- type B = {
- def b: Int
- }
-
- type AB = A & B
-
- def f(ab: AB): AB = ab
-
- f(new {
- def a = 43
- def b = 42
- })
-} \ No newline at end of file
diff --git a/tests/pos/t1053.scala b/tests/pos/t1053.scala
index 1d4dfb637..2c5dc1d5a 100644
--- a/tests/pos/t1053.scala
+++ b/tests/pos/t1053.scala
@@ -1,6 +1,7 @@
trait T[A] { trait U { type W = A; val x = 3 } }
+trait Base { type V }
object Test {
- val x : ({ type V = T[this.type] })#V = null
+ val x : (Base { type V = T[this.type] })#V = null
val y = new x.U { }
}
diff --git a/tests/pos/t2810.scala b/tests/pos/t2810.scala
deleted file mode 100644
index c85eca164..000000000
--- a/tests/pos/t2810.scala
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-object Test {
- val closeable1: { def close(): Unit } = new scala.io.Source { val iter: Iterator[Char] = "".iterator }
- val closeable2: { def close(): Unit } = new java.io.Closeable { def close() = {} }
-}
diff --git a/tests/pos/typers.scala b/tests/pos/typers.scala
index fe11ca602..7f67d2c72 100644
--- a/tests/pos/typers.scala
+++ b/tests/pos/typers.scala
@@ -88,6 +88,7 @@ object typers {
}
class Refinements {
+ trait C { type T; def process(x: T): Int }
val y: C { type T; val key: T; def process(x: T): Int } = ???
}
diff --git a/tests/pos/zoo.scala b/tests/pos/zoo.scala
index 08f7eba63..02dac8f5b 100644
--- a/tests/pos/zoo.scala
+++ b/tests/pos/zoo.scala
@@ -1,40 +1,37 @@
object Test {
-type Meat = {
+trait FoodStuff
+trait Meat extends FoodStuff {
type IsMeat = Any
}
-type Grass = {
+trait Grass extends FoodStuff {
type IsGrass = Any
}
-type Animal = {
- type Food
+trait Animal {
+ type Food <: FoodStuff
def eats(food: Food): Unit
def gets: Food
}
-type Cow = {
+trait Cow extends Animal {
type IsMeat = Any
type Food <: Grass
def eats(food: Grass): Unit
- def gets: Grass
+ def gets: Food
}
-type Lion = {
+trait Lion extends Animal {
type Food = Meat
def eats(food: Meat): Unit
def gets: Meat
}
-def newMeat: Meat = new {
- type IsMeat = Any
+def newMeat: Meat = new Meat {
}
-def newGrass: Grass = new {
- type IsGrass = Any
+def newGrass: Grass = new Grass {
}
-def newCow: Cow = new {
- type IsMeat = Any
+def newCow: Cow = new Cow {
type Food = Grass
def eats(food: Grass) = ()
def gets = newGrass
}
-def newLion: Lion = new {
- type Food = Meat
+def newLion: Lion = new Lion {
def eats(food: Meat) = ()
def gets = newMeat
}