aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/core/Types.scala7
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala6
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala2
-rw-r--r--test/dotc/tests.scala1
-rw-r--r--tests/neg/projections.scala7
-rw-r--r--tests/pos/projections.scala14
6 files changed, 30 insertions, 7 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 89facfee5..827e851a9 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -117,14 +117,15 @@ object Types {
}
/** A type T is a legal prefix in a type selection T#A if
- * T is stable or T contains no abstract types
+ * T is stable or T contains no abstract types except possibly A.
* !!! Todo: What about non-final vals that contain abstract types?
*/
- final def isLegalPrefix(implicit ctx: Context): Boolean =
+ final def isLegalPrefixFor(selector: Name)(implicit ctx: Context): Boolean =
isStable || {
val absTypeNames = memberNames(abstractTypeNameFilter)
if (absTypeNames.nonEmpty) typr.println(s"abstract type members of ${this.showWithUnderlying()}: $absTypeNames")
- absTypeNames.isEmpty
+ absTypeNames.isEmpty ||
+ absTypeNames.head == selector && absTypeNames.tail.isEmpty
}
/** Is this type guaranteed not to have `null` as a value?
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 5e52c5d7e..7da00e051 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -51,8 +51,8 @@ trait Checking {
/** Check that type `tp` is a legal prefix for '#'.
* @return The type itself
*/
- def checkLegalPrefix(tp: Type, pos: Position)(implicit ctx: Context): Unit =
- if (!tp.isLegalPrefix) ctx.error(d"$tp is not a valid prefix for '#'", pos)
+ def checkLegalPrefix(tp: Type, selector: Name, pos: Position)(implicit ctx: Context): Unit =
+ if (!tp.isLegalPrefixFor(selector)) ctx.error(d"$tp is not a valid prefix for '# $selector'", pos)
/** Check that `tp` is a class type with a stable prefix. Also, if `isFirst` is
* false check that `tp` is a trait.
@@ -139,7 +139,7 @@ trait NoChecking extends Checking {
override def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = tree
override def checkBounds(args: List[tpd.Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit = ()
override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
- override def checkLegalPrefix(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
+ override def checkLegalPrefix(tp: Type, selector: Name, pos: Position)(implicit ctx: Context): Unit = ()
override def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type = tp
override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = ()
override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index d6b724270..c01cf714f 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -277,7 +277,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = track("typedSelectFromTypeTree") {
val qual1 = typedType(tree.qualifier, selectionProto(tree.name, pt, this))
- checkLegalPrefix(qual1.tpe, qual1.pos)
+ checkLegalPrefix(qual1.tpe, tree.name, qual1.pos)
assignType(cpy.SelectFromTypeTree(tree, qual1, tree.name), qual1)
}
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index c7b0dc044..64d520500 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -67,6 +67,7 @@ class tests extends CompilerTest {
@Test def neg_autoTupling = compileFile(posDir, "autoTuplingTest", "-language:noAutoTupling" :: Nil, xerrors = 4)
@Test def neg_autoTupling2 = compileFile(negDir, "autoTuplingTest", xerrors = 4)
@Test def neg_companions = compileFile(negDir, "companions", xerrors = 1)
+ @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_t0273_doubledefs = compileFile(negDir, "t0273", xerrors = 1)
diff --git a/tests/neg/projections.scala b/tests/neg/projections.scala
new file mode 100644
index 000000000..5d80e1151
--- /dev/null
+++ b/tests/neg/projections.scala
@@ -0,0 +1,7 @@
+class projections {
+
+ class Lambda { type Arg; type Apply }
+
+ var x: (Lambda { type Apply = Int }) # Apply = _ // error: illegal prefix
+
+}
diff --git a/tests/pos/projections.scala b/tests/pos/projections.scala
new file mode 100644
index 000000000..894a00bcf
--- /dev/null
+++ b/tests/pos/projections.scala
@@ -0,0 +1,14 @@
+class projections {
+
+ class Lambda { type Arg; type Apply }
+
+ var x: (Lambda { type Apply = Int; type Arg = String }) # Apply = _
+ var y: Int = _
+ x = y
+ y = x
+
+ var xx: (Lambda { type Apply = Arg } { type Arg = Int }) # Apply = _
+ xx = y
+ y = xx
+
+}