Skip to content

Commit 61cb51a

Browse files
oderskyDarkDimius
authored andcommitted
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.
1 parent 3f5d15d commit 61cb51a

13 files changed

+98
-89
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
801801
typr.println(s"adding refinement $refinement")
802802
checkRefinementNonCyclic(refinement, refineCls, seen)
803803
val rsym = refinement.symbol
804+
if ((rsym.is(Method) || rsym.isType) && rsym.allOverriddenSymbols.isEmpty) {
805+
println(refineCls.baseClasses)
806+
ctx.error(i"refinement $rsym without matching type in parent $parent", refinement.pos)
807+
}
804808
val rinfo = if (rsym is Accessor) rsym.info.resultType else rsym.info
805809
RefinedType(parent, rsym.name, rt => rinfo.substThis(refineCls, SkolemType(rt)))
806810
// todo later: check that refinement is within bounds

test/dotc/tests.scala

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ class tests extends CompilerTest {
5656
@Test def pos_overrides() = compileFile(posDir, "overrides")
5757
@Test def pos_javaOverride() = compileDir(posDir + "java-override")
5858
@Test def pos_templateParents() = compileFile(posDir, "templateParents")
59-
@Test def pos_structural() = compileFile(posDir, "structural")
6059
@Test def pos_overloadedAccess = compileFile(posDir, "overloadedAccess")
6160
@Test def pos_approximateUnion = compileFile(posDir, "approximateUnion")
6261
@Test def pos_tailcall = compileDir(posDir + "tailcall/")
@@ -87,16 +86,10 @@ class tests extends CompilerTest {
8786
@Test def neg_over = compileFile(negDir, "over", xerrors = 3)
8887
@Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 11)
8988
@Test def neg_projections = compileFile(negDir, "projections", xerrors = 1)
90-
@Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1)
91-
@Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4)
89+
@Test def neg_i39 = compileFile(negDir, "i39", xerrors = 2)
90+
@Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 6)
9291
@Test def neg_t0273_doubledefs = compileFile(negDir, "t0273", xerrors = 1)
93-
@Test def neg_t0586_structural = compileFile(negDir, "t0586", xerrors = 1)
94-
@Test def neg_t0625_structural = compileFile(negDir, "t0625", xerrors = 1)(
95-
defaultOptions = noCheckOptions)
96-
// -Ycheck fails because there are structural types involving higher-kinded types.
97-
// these are illegal, but are tested only later.
98-
@Test def neg_t1131_structural = compileFile(negDir, "t1131", xerrors = 1)
99-
@Test def neg_zoo = compileFile(negDir, "zoo", xerrors = 1)
92+
@Test def neg_zoo = compileFile(negDir, "zoo", xerrors = 12)
10093
@Test def neg_t1192_legalPrefix = compileFile(negDir, "t1192", xerrors = 1)
10194
@Test def neg_tailcall_t1672b = compileFile(negDir, "tailcall/t1672b", xerrors = 6)
10295
@Test def neg_tailcall_t3275 = compileFile(negDir, "tailcall/t3275", xerrors = 1)
@@ -108,13 +101,13 @@ class tests extends CompilerTest {
108101
@Test def neg_t1843_variances = compileFile(negDir, "t1843-variances", xerrors = 1)
109102
@Test def neg_t2660_ambi = compileFile(negDir, "t2660", xerrors = 2)
110103
@Test def neg_t2994 = compileFile(negDir, "t2994", xerrors = 2)
111-
@Test def neg_subtyping = compileFile(negDir, "subtyping", xerrors = 2)
104+
@Test def neg_subtyping = compileFile(negDir, "subtyping", xerrors = 4)
112105
@Test def neg_variances = compileFile(negDir, "variances", xerrors = 2)
113106
@Test def neg_badAuxConstr = compileFile(negDir, "badAuxConstr", xerrors = 2)
114107
@Test def neg_typetest = compileFile(negDir, "typetest", xerrors = 1)
115108
@Test def neg_t1569_failedAvoid = compileFile(negDir, "t1569-failedAvoid", xerrors = 1)
116109
@Test def neg_cycles = compileFile(negDir, "cycles", xerrors = 8)
117-
@Test def neg_boundspropagation = compileFile(negDir, "boundspropagation", xerrors = 4)
110+
@Test def neg_boundspropagation = compileFile(negDir, "boundspropagation", xerrors = 5)
118111
@Test def neg_refinedSubtyping = compileFile(negDir, "refinedSubtyping", xerrors = 2)
119112
@Test def neg_i0091_infpaths = compileFile(negDir, "i0091-infpaths", xerrors = 3)
120113
@Test def neg_i0248_inherit_refined = compileFile(negDir, "i0248-inherit-refined", xerrors = 4)

tests/neg/structural.scala

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package p1 {
2+
3+
object test123 {
4+
type A = { def a: Int }
5+
def f(a: A): A = a
6+
}
7+
8+
object structural2 {
9+
type A = { def a: Int }
10+
11+
type B = {
12+
def b: Int
13+
}
14+
15+
type AB = A & B
16+
17+
def f(ab: AB): AB = ab
18+
19+
f(new {
20+
def a = 43
21+
def b = 42
22+
})
23+
}
24+
}
25+
26+
package p2 {
27+
object RClose {
28+
type ReflectCloseable = { def close(): Unit }
29+
def withReflectCloseable[T <: ReflectCloseable, R](s: T)(action: T => R): R =
30+
try {
31+
action(s)
32+
} finally {
33+
s.close()
34+
}
35+
}
36+
}
37+
38+
package p3 {
39+
object Test {
40+
def idMap[C[_],T](m: { def map[U](f: T => U): C[U] }): C[T] = m.map(t => t)
41+
42+
def main(args: Array[String]): Unit = {
43+
idMap(Some(5))
44+
idMap(Responder.constant(5))
45+
}
46+
}
47+
}
48+
package p4 {
49+
50+
trait A { self: Any { def p: Any } =>
51+
def f(b: => Unit): Unit = {}
52+
f { p } // error: cannot access member 'p' from structural type
53+
}
54+
}
55+
56+
package p5 {
57+
// t2810
58+
object Test {
59+
val closeable1: { def close(): Unit } = new scala.io.Source { val iter: Iterator[Char] = "".iterator }
60+
val closeable2: { def close(): Unit } = new java.io.Closeable { def close() = {} }
61+
}
62+
}
63+
64+
package p6 {
65+
66+
class Refinements {
67+
val y: C { val x: T; type T } // was adeprecated warning: illegal forward reference in refinement; now illegal
68+
}
69+
70+
}

tests/neg/t0586.scala

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

tests/neg/t0625.scala

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

tests/neg/t1131.scala

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

tests/neg/typers.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,4 @@ object typers {
6060
123
6161
}
6262
}
63-
64-
class Refinements {
65-
val y: C { val x: T; type T } // deprecated warning: illegal forward reference in refinement
66-
}
6763
}

tests/pos/i262-null-subtyping.scala

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
object O {
2-
// This compiles
3-
val a: { type T } = null;
4-
val b: Any { type T } = null;
2+
trait Base extends Any { type T }
3+
val a: Base { type T } = null;
4+
val b: Any with Base { type T } = null;
55

6-
// This doesn't:
7-
// found : Null
8-
// required: AnyRef{T}
9-
val c: AnyRef { type T } = null;
6+
val c: AnyRef with Base { type T } = null;
107

118
class A
129
class B

tests/pos/structural.scala

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

tests/pos/t1053.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
trait T[A] { trait U { type W = A; val x = 3 } }
2+
trait Base { type V }
23

34
object Test {
4-
val x : ({ type V = T[this.type] })#V = null
5+
val x : (Base { type V = T[this.type] })#V = null
56
val y = new x.U { }
67
}

tests/pos/t2810.scala

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

tests/pos/typers.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ object typers {
8888
}
8989

9090
class Refinements {
91+
trait C { type T; def process(x: T): Int }
9192
val y: C { type T; val key: T; def process(x: T): Int } = ???
9293
}
9394

tests/pos/zoo.scala

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,37 @@
11
object Test {
2-
type Meat = {
2+
trait FoodStuff
3+
trait Meat extends FoodStuff {
34
type IsMeat = Any
45
}
5-
type Grass = {
6+
trait Grass extends FoodStuff {
67
type IsGrass = Any
78
}
8-
type Animal = {
9-
type Food
9+
trait Animal {
10+
type Food <: FoodStuff
1011
def eats(food: Food): Unit
1112
def gets: Food
1213
}
13-
type Cow = {
14+
trait Cow extends Animal {
1415
type IsMeat = Any
1516
type Food <: Grass
1617
def eats(food: Grass): Unit
17-
def gets: Grass
18+
def gets: Food
1819
}
19-
type Lion = {
20+
trait Lion extends Animal {
2021
type Food = Meat
2122
def eats(food: Meat): Unit
2223
def gets: Meat
2324
}
24-
def newMeat: Meat = new {
25-
type IsMeat = Any
25+
def newMeat: Meat = new Meat {
2626
}
27-
def newGrass: Grass = new {
28-
type IsGrass = Any
27+
def newGrass: Grass = new Grass {
2928
}
30-
def newCow: Cow = new {
31-
type IsMeat = Any
29+
def newCow: Cow = new Cow {
3230
type Food = Grass
3331
def eats(food: Grass) = ()
3432
def gets = newGrass
3533
}
36-
def newLion: Lion = new {
37-
type Food = Meat
34+
def newLion: Lion = new Lion {
3835
def eats(food: Meat) = ()
3936
def gets = newMeat
4037
}

0 commit comments

Comments
 (0)