diff options
author | Martin Odersky <odersky@gmail.com> | 2015-02-12 11:28:35 +0100 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2015-03-18 11:09:43 +0100 |
commit | 61cb51acaedbe603add8c4af9e390a27f8b33f09 (patch) | |
tree | 2e6f7d2410b96b208b3f6be5c5465a320751d7f0 | |
parent | 3f5d15defa7481da1b9d1f20e91569a340c71e8e (diff) | |
download | dotty-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.scala | 4 | ||||
-rw-r--r-- | test/dotc/tests.scala | 17 | ||||
-rw-r--r-- | tests/neg/structural.scala | 70 | ||||
-rw-r--r-- | tests/neg/t0586.scala | 9 | ||||
-rw-r--r-- | tests/neg/t0625.scala | 8 | ||||
-rw-r--r-- | tests/neg/t1131.scala | 4 | ||||
-rw-r--r-- | tests/neg/typers.scala | 4 | ||||
-rw-r--r-- | tests/pos/i262-null-subtyping.scala | 11 | ||||
-rw-r--r-- | tests/pos/structural.scala | 21 | ||||
-rw-r--r-- | tests/pos/t1053.scala | 3 | ||||
-rw-r--r-- | tests/pos/t2810.scala | 8 | ||||
-rw-r--r-- | tests/pos/typers.scala | 1 | ||||
-rw-r--r-- | tests/pos/zoo.scala | 27 |
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 } |