Skip to content

Commit 54eaf64

Browse files
committed
Check that non-abstract classes have realizable bounds.
1 parent 7e0affb commit 54eaf64

File tree

4 files changed

+41
-14
lines changed

4 files changed

+41
-14
lines changed

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

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -408,16 +408,21 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
408408
case _ => false
409409
}
410410
if (!isConcrete(tp)) NotConcrete
411-
else {
412-
def hasBadBounds(mbr: SingleDenotation) = {
413-
val bounds = mbr.info.bounds
414-
!(bounds.lo <:< bounds.hi)
415-
}
416-
tp.nonClassTypeMembers.find(hasBadBounds) match {
417-
case Some(mbr) => new HasProblemBounds(mbr)
418-
case _ => Realizable
419-
}
420-
}
411+
else boundsRealizability(tp)
412+
}
413+
414+
/** `Realizable` is `tp` has good bounds, a `HasProblemBounds` instance
415+
* pointing to a bad bounds member otherwise.
416+
*/
417+
def boundsRealizability(tp: Type)(implicit ctx: Context) = {
418+
def hasBadBounds(mbr: SingleDenotation) = {
419+
val bounds = mbr.info.bounds
420+
!(bounds.lo <:< bounds.hi)
421+
}
422+
tp.nonClassTypeMembers.find(hasBadBounds) match {
423+
case Some(mbr) => new HasProblemBounds(mbr)
424+
case _ => Realizable
425+
}
421426
}
422427

423428
private def enterArgBinding(formal: Symbol, info: Type, cls: ClassSymbol, decls: Scope) = {

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,13 @@ trait Checking {
330330
}
331331
}
332332

333+
/** Check that all type members of `tp` have realizable bounds */
334+
def checkRealizableBounds(tp: Type, pos: Position)(implicit ctx: Context): Unit = {
335+
val rstatus = ctx.boundsRealizability(tp)
336+
if (rstatus ne TypeOps.Realizable)
337+
ctx.error(i"$tp cannot be instantiated since it${rstatus.msg}", pos)
338+
}
339+
333340
/** Check that `tp` is a class type with a stable prefix. Also, if `traitReq` is
334341
* true check that `tp` is a trait.
335342
* Stability checking is disabled in phases after RefChecks.

test/dotc/tests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ class tests extends CompilerTest {
156156
@Test def neg_i705 = compileFile(negDir, "i705-inner-value-class", xerrors = 7)
157157
@Test def neg_i866 = compileFile(negDir, "i866", xerrors = 2)
158158
@Test def neg_i974 = compileFile(negDir, "i974", xerrors = 2)
159-
@Test def neg_i1050 = compileFile(negDir, "i1050", xerrors = 8)
159+
@Test def neg_i1050 = compileFile(negDir, "i1050", xerrors = 11)
160160
@Test def neg_i1050a = compileFile(negDir, "i1050a", xerrors = 2)
161161
@Test def neg_moduleSubtyping = compileFile(negDir, "moduleSubtyping", xerrors = 4)
162162
@Test def neg_escapingRefs = compileFile(negDir, "escapingRefs", xerrors = 2)

tests/neg/i1050.scala

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,21 @@ object Tiark3 {
7979
val v = new V {}
8080
v.brand("boom!"): Nothing
8181
}
82+
object Tiark4 {
83+
trait U {
84+
type Y
85+
trait X { type L = Y }
86+
def compute: X
87+
final lazy val p: X = compute
88+
def brand(x: Y): p.L = x
89+
}
90+
trait V extends U {
91+
type Y >: Any <: Nothing
92+
def compute: X = ???
93+
}
94+
val v = new V {} // error: cannot be instantiated
95+
v.brand("boom!")
96+
}
8297
object Import {
8398
trait A { type L <: Nothing }
8499
trait B { type L >: Any}
@@ -90,7 +105,7 @@ object Import {
90105
val x: L = ??? // error: nonfinal lazy
91106
}
92107
}
93-
trait V extends U {
94-
lazy val p: A & B = ???
95108
}
96-
109+
object V { // error: cannot be instantiated
110+
type Y >: Any <: Nothing // error: only classes can have declared but undefined members
111+
}

0 commit comments

Comments
 (0)