Skip to content

Commit f9025c9

Browse files
committed
Heal member-select on opaque reference
When the prefix of an opaque isn't the .this reference of the module class, then its RHS isn't visible. TypeComparer uses ctx.owner to "heal" or "lift" this type such that it is. We reuse that logic for member selection.
1 parent c4ddadb commit f9025c9

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed

Diff for: compiler/src/dotty/tools/dotc/typer/Typer.scala

+11
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
712712
typedSelectWithAdapt(tree, pt, qual)
713713
else EmptyTree
714714

715+
def tryLiftToThis() =
716+
val wtp = qual.tpe.widen
717+
val liftedTp = comparing(_.liftToThis(wtp))
718+
if liftedTp ne wtp then
719+
val qual1 = qual.cast(liftedTp)
720+
val tree1 = cpy.Select(tree0)(qual1, selName)
721+
val rawType1 = selectionType(tree1, qual1)
722+
tryType(tree1, qual1, rawType1)
723+
else EmptyTree
724+
715725
def trySmallGenericTuple(tree: untpd.Select, qual: Tree, withCast: Boolean) =
716726
if qual.tpe.isSmallGenericTuple then
717727
if withCast then
@@ -761,6 +771,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
761771
tryType(tree, qual, rawType)
762772
.orElse(trySimplifyApply())
763773
.orElse(tryInstantiateTypeVar())
774+
.orElse(tryLiftToThis())
764775
.orElse(trySmallGenericTuple(tree, qual, withCast = true))
765776
.orElse(tryExt(tree, qual))
766777
.orElse(tryGadt(tree))

Diff for: tests/pos/i19609.orig.scala

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
object o {
2+
opaque type T = String
3+
4+
summon[o.T =:= T] // OK
5+
summon[o.T =:= String] // OK
6+
7+
def test1(t: T): Int =
8+
t.length // OK
9+
10+
def test2(t: o.T): Int =
11+
t.length // Error: value length is not a member of Playground.o.T
12+
}

Diff for: tests/pos/i19609.scala

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
object o { u =>
2+
opaque type T = String
3+
4+
def st = summon[String =:= T]
5+
def su = summon[String =:= u.T]
6+
def so = summon[String =:= o.T]
7+
8+
def ts = summon[T =:= String]
9+
def tu = summon[T =:= u.T]
10+
def to = summon[T =:= o.T]
11+
12+
def us = summon[u.T =:= String]
13+
def ut = summon[u.T =:= T]
14+
def uo = summon[u.T =:= o.T]
15+
16+
def os = summon[o.T =:= String]
17+
def ot = summon[o.T =:= T]
18+
def ou = summon[o.T =:= u.T]
19+
20+
def ms(x: String): Int = x.length // ok
21+
def mt(x: T): Int = x.length // ok
22+
def mu(x: u.T): Int = x.length // ok
23+
def mo(x: o.T): Int = x.length // was: error: value length is not a member of o.T
24+
}

0 commit comments

Comments
 (0)