aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala25
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala7
-rw-r--r--test/dotc/tests.scala2
-rw-r--r--tests/neg/i1050.scala21
4 files changed, 41 insertions, 14 deletions
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index 882ab9f10..227dbb90f 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -449,16 +449,21 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
case _ => false
}
if (!isConcrete(tp)) NotConcrete
- else {
- def hasBadBounds(mbr: SingleDenotation) = {
- val bounds = mbr.info.bounds
- !(bounds.lo <:< bounds.hi)
- }
- tp.nonClassTypeMembers.find(hasBadBounds) match {
- case Some(mbr) => new HasProblemBounds(mbr)
- case _ => Realizable
- }
- }
+ else boundsRealizability(tp)
+ }
+
+ /** `Realizable` is `tp` has good bounds, a `HasProblemBounds` instance
+ * pointing to a bad bounds member otherwise.
+ */
+ def boundsRealizability(tp: Type)(implicit ctx: Context) = {
+ def hasBadBounds(mbr: SingleDenotation) = {
+ val bounds = mbr.info.bounds
+ !(bounds.lo <:< bounds.hi)
+ }
+ tp.nonClassTypeMembers.find(hasBadBounds) match {
+ case Some(mbr) => new HasProblemBounds(mbr)
+ case _ => Realizable
+ }
}
private def enterArgBinding(formal: Symbol, info: Type, cls: ClassSymbol, decls: Scope) = {
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index ca7c5c5ab..7e90d755b 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -330,6 +330,13 @@ trait Checking {
}
}
+ /** Check that all type members of `tp` have realizable bounds */
+ def checkRealizableBounds(tp: Type, pos: Position)(implicit ctx: Context): Unit = {
+ val rstatus = ctx.boundsRealizability(tp)
+ if (rstatus ne TypeOps.Realizable)
+ ctx.error(i"$tp cannot be instantiated since it${rstatus.msg}", pos)
+ }
+
/** Check that `tp` is a class type with a stable prefix. Also, if `traitReq` is
* true check that `tp` is a trait.
* Stability checking is disabled in phases after RefChecks.
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index e1a10a6e2..47ac00c6f 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -162,7 +162,7 @@ class tests extends CompilerTest {
@Test def neg_i803 = compileFile(negDir, "i803", xerrors = 2)
@Test def neg_i866 = compileFile(negDir, "i866", xerrors = 2)
@Test def neg_i974 = compileFile(negDir, "i974", xerrors = 2)
- @Test def neg_i1050 = compileFile(negDir, "i1050", xerrors = 8)
+ @Test def neg_i1050 = compileFile(negDir, "i1050", xerrors = 11)
@Test def neg_i1050a = compileFile(negDir, "i1050a", xerrors = 2)
@Test def neg_moduleSubtyping = compileFile(negDir, "moduleSubtyping", xerrors = 4)
@Test def neg_escapingRefs = compileFile(negDir, "escapingRefs", xerrors = 2)
diff --git a/tests/neg/i1050.scala b/tests/neg/i1050.scala
index 25e647a57..5808011fa 100644
--- a/tests/neg/i1050.scala
+++ b/tests/neg/i1050.scala
@@ -79,6 +79,21 @@ object Tiark3 {
val v = new V {}
v.brand("boom!"): Nothing
}
+object Tiark4 {
+ trait U {
+ type Y
+ trait X { type L = Y }
+ def compute: X
+ final lazy val p: X = compute
+ def brand(x: Y): p.L = x
+ }
+ trait V extends U {
+ type Y >: Any <: Nothing
+ def compute: X = ???
+ }
+ val v = new V {} // error: cannot be instantiated
+ v.brand("boom!")
+}
object Import {
trait A { type L <: Nothing }
trait B { type L >: Any}
@@ -90,7 +105,7 @@ object Import {
val x: L = ??? // error: nonfinal lazy
}
}
- trait V extends U {
- lazy val p: A & B = ???
}
-
+object V { // error: cannot be instantiated
+ type Y >: Any <: Nothing // error: only classes can have declared but undefined members
+}