Skip to content

Commit 51563ae

Browse files
committed
Change definition of isLegalPrefix so that it allows projecting on an abstract type.
This is needed to make the encoding og higher-kinded types work. E.g. Rep[Int] would be represented as Rep { type Arg$0 = Int } # Apply where Apply is an abstract member of the base class Lambfa$I of Rep.
1 parent c2175ec commit 51563ae

File tree

6 files changed

+30
-7
lines changed

6 files changed

+30
-7
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,15 @@ object Types {
117117
}
118118

119119
/** A type T is a legal prefix in a type selection T#A if
120-
* T is stable or T contains no abstract types
120+
* T is stable or T contains no abstract types except possibly A.
121121
* !!! Todo: What about non-final vals that contain abstract types?
122122
*/
123-
final def isLegalPrefix(implicit ctx: Context): Boolean =
123+
final def isLegalPrefixFor(selector: Name)(implicit ctx: Context): Boolean =
124124
isStable || {
125125
val absTypeNames = memberNames(abstractTypeNameFilter)
126126
if (absTypeNames.nonEmpty) typr.println(s"abstract type members of ${this.showWithUnderlying()}: $absTypeNames")
127-
absTypeNames.isEmpty
127+
absTypeNames.isEmpty ||
128+
absTypeNames.head == selector && absTypeNames.tail.isEmpty
128129
}
129130

130131
/** Is this type guaranteed not to have `null` as a value?

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ trait Checking {
5151
/** Check that type `tp` is a legal prefix for '#'.
5252
* @return The type itself
5353
*/
54-
def checkLegalPrefix(tp: Type, pos: Position)(implicit ctx: Context): Unit =
55-
if (!tp.isLegalPrefix) ctx.error(d"$tp is not a valid prefix for '#'", pos)
54+
def checkLegalPrefix(tp: Type, selector: Name, pos: Position)(implicit ctx: Context): Unit =
55+
if (!tp.isLegalPrefixFor(selector)) ctx.error(d"$tp is not a valid prefix for '# $selector'", pos)
5656

5757
/** Check that `tp` is a class type with a stable prefix. Also, if `isFirst` is
5858
* false check that `tp` is a trait.
@@ -139,7 +139,7 @@ trait NoChecking extends Checking {
139139
override def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = tree
140140
override def checkBounds(args: List[tpd.Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit = ()
141141
override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
142-
override def checkLegalPrefix(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
142+
override def checkLegalPrefix(tp: Type, selector: Name, pos: Position)(implicit ctx: Context): Unit = ()
143143
override def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type = tp
144144
override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = ()
145145
override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
277277

278278
def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = track("typedSelectFromTypeTree") {
279279
val qual1 = typedType(tree.qualifier, selectionProto(tree.name, pt, this))
280-
checkLegalPrefix(qual1.tpe, qual1.pos)
280+
checkLegalPrefix(qual1.tpe, tree.name, qual1.pos)
281281
assignType(cpy.SelectFromTypeTree(tree, qual1, tree.name), qual1)
282282
}
283283

test/dotc/tests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class tests extends CompilerTest {
6767
@Test def neg_autoTupling = compileFile(posDir, "autoTuplingTest", "-language:noAutoTupling" :: Nil, xerrors = 4)
6868
@Test def neg_autoTupling2 = compileFile(negDir, "autoTuplingTest", xerrors = 4)
6969
@Test def neg_companions = compileFile(negDir, "companions", xerrors = 1)
70+
@Test def neg_projections = compileFile(negDir, "projections", xerrors = 1)
7071
@Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1)
7172
@Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4)
7273
@Test def neg_t0273_doubledefs = compileFile(negDir, "t0273", xerrors = 1)

tests/neg/projections.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class projections {
2+
3+
class Lambda { type Arg; type Apply }
4+
5+
var x: (Lambda { type Apply = Int }) # Apply = _ // error: illegal prefix
6+
7+
}

tests/pos/projections.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class projections {
2+
3+
class Lambda { type Arg; type Apply }
4+
5+
var x: (Lambda { type Apply = Int; type Arg = String }) # Apply = _
6+
var y: Int = _
7+
x = y
8+
y = x
9+
10+
var xx: (Lambda { type Apply = Arg } { type Arg = Int }) # Apply = _
11+
xx = y
12+
y = xx
13+
14+
}

0 commit comments

Comments
 (0)