Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,18 @@ trait TypeAssigner {
else
qualType

def maybeSkolemizePrefix(tree: untpd.Tree, qualType: Type, name: Name)(using Context): Type =
if name.isTermName && !TypeOps.isLegalPrefix(qualType) then
tree.getAttachment(QualSkolem) match
case Some(skolem) if skolem.info == qualType =>
skolem
case _ =>
val skolem = QualSkolemType(qualType)
tree.putAttachment(QualSkolem, skolem)
skolem
else
qualType

/** The type of the selection `tree`, where `qual1` is the typed qualifier part. */
def selectionType(tree: untpd.RefTree, qual1: Tree)(using Context): Type =
val qualType =
Expand Down Expand Up @@ -155,7 +167,7 @@ trait TypeAssigner {
// is casted to T[] by javac. Since the return type of Array[T]#clone() is Array[T],
// this is exactly what Erasure will do.
case _ =>
val pre = maybeSkolemizePrefix(qualType, name)
val pre = maybeSkolemizePrefix(tree, qualType, name)
val mbr =
if ctx.isJava then
// don't look in the companion class here if qual is a module,
Expand Down Expand Up @@ -621,6 +633,11 @@ object TypeAssigner extends TypeAssigner:
*/
private[dotc] val SkolemizedArgs = new Property.StickyKey[Map[tpd.Tree, SkolemType]]

/** An attachment on a selection holding the `QualSkolemType` used to type it.
* Sticky so that copies of the tree (e.g. while inlining) keep the same skolem.
*/
private[dotc] val QualSkolem = new Property.StickyKey[QualSkolemType]

def seqLitType(tree: untpd.SeqLiteral, elemType: Type)(using Context) = tree match
case tree: untpd.JavaSeqLiteral => defn.ArrayOf(elemType)
case _ => if ctx.erasedTypes then defn.SeqType else defn.SeqType.appliedTo(elemType)
4 changes: 4 additions & 0 deletions compiler/test/dotc/run-test-pickling.excludelist
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,9 @@ typeCheckErrors.scala
i18150.scala
i22968.scala

# Unstable-prefix selection: typer skolemizes, unpickling recomputes without skolem
# so info goes from Box[(Owner#w : Int)] to Box[? <: (Owner#w : Int)]. Separate fix later.
i26681.scala

# Pickling differences with local parameters export forwarders of methods with into parameters. But their external type is the same
Parser.scala
16 changes: 16 additions & 0 deletions tests/neg/i26681b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// https://github.com/scala/scala3/issues/26681
class Box[T](val x: T)

class Owner:
val w: Int = 8
val b: Box[w.type] = new Box(w)
def get: Box[w.type] = new Box(w)
def set(bb: Box[w.type]): Unit = ()

def unstable: Owner = new Owner

def same[T](a: Box[T], b: Box[T]): Unit = ()

def t1 = same(unstable.b, unstable.b) // error
def t2 = same(unstable.get, unstable.get) // error
def t3 = unstable.set(unstable.get) // error
2 changes: 2 additions & 0 deletions tests/run/i26681.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ok
ok
19 changes: 19 additions & 0 deletions tests/run/i26681.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// https://github.com/scala/scala3/issues/26681
class Box[T]

class Owner:
val w: Int = 8
val b: Box[w.type] = new Box[w.type]

def use[T](b: Box[T]): String = "ok"

def unstable: Owner = new Owner

transparent inline def f(inline rhs: Any): Any =
inline rhs match
case r: Box[t] => use[t](r)

@main def Test =
println(f(unstable.b))
val o = unstable
println(f(o.b))
Loading