Skip to content

WIP: fix opaque type proxy regression: Do not compare opaque types by name #23030

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
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
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2968,7 +2968,10 @@ object Types extends TypeUtils {
if myCanDropAliasPeriod != ctx.period then
myCanDropAlias =
!symbol.canMatchInheritedSymbols
|| !prefix.baseClasses.exists(_.info.decls.lookup(name).is(Deferred))
|| !prefix.baseClasses.exists{cls =>
val decl = cls.info.decls.lookup(name)
decl.is(Deferred) && !decl.is(Opaque)
}
myCanDropAliasPeriod = ctx.period
myCanDropAlias

Expand Down
19 changes: 16 additions & 3 deletions compiler/src/dotty/tools/dotc/inlines/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -476,9 +476,18 @@ class Inliner(val call: tpd.Tree)(using Context):
fixRefinedTypes(parent)
case _ =>
fixRefinedTypes(binding.symbol.info)
val prev = binding.symbol.info
binding.symbol.info = mapOpaques.typeMap(binding.symbol.info)
mapOpaques.transform(binding).asInstanceOf[ValDef]
val mapped = mapOpaques.transform(binding).asInstanceOf[ValDef]
.showing(i"transformed this binding exposing opaque aliases: $result", inlining)
// val res =
// if binding.symbol.info != prev then
// binding.symbol.info = AndType(prev, binding.symbol.info)
// ValDef(binding.symbol.asTerm, mapped.rhs.cast(binding.symbol.info)) // TODO merge
// else
// mapped
// res
mapped
end addProxiesForRecurrentOpaques

/** If `binding` contains TermRefs that refer to objects with opaque
Expand Down Expand Up @@ -561,7 +570,7 @@ class Inliner(val call: tpd.Tree)(using Context):
// LambdaTypeTree parameters also have the inlineMethod as owner. C.f. i13460.scala.
&& !paramProxy.contains(tpe) =>
paramBinding.get(tpe.name) match
case Some(bound) => paramProxy(tpe) = bound
case Some(bound) => paramProxy(tpe) = mapOpaques.typeMap(bound)
case _ => // can happen for params bound by type-lambda trees.

// The widened type may contain param types too (see tests/pos/i12379a.scala)
Expand Down Expand Up @@ -912,7 +921,11 @@ class Inliner(val call: tpd.Tree)(using Context):
sym.info = rhs.tpe
untpd.cpy.ValDef(vdef)(vdef.name, untpd.TypeTree(rhs.tpe), untpd.TypedSplice(rhs))
else vdef
super.typedValDef(vdef1, sym)
if vdef.name.toString.contains("$proxy") then // TODO look for a better solution
// AndType(t1, t2) might not equal &(t1, t2),
// but when constructing proxies we have to use AndType without simplyfying the types
vdef.asInstanceOf[Tree]
else super.typedValDef(vdef1, sym)

override def typedApply(tree: untpd.Apply, pt: Type)(using Context): Tree =
val locked = ctx.typerState.ownedVars
Expand Down
14 changes: 14 additions & 0 deletions tests/pos/i22974/Maybe_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package pack
import Maybe._
opaque type Maybe[+A] >: (Absent | Present[A]) = Absent | Present[A]
object Maybe:
sealed abstract class Absent
case object Absent extends Absent
object internal:
case class PresentAbsent(val depth: Int)
opaque type Present[+A] = A | internal.PresentAbsent

extension [A](self: Maybe[A]) {
inline def flatten[B]: Maybe[B] = ???
inline def isDefined: Boolean = ???
}
6 changes: 6 additions & 0 deletions tests/pos/i22974/macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import scala.quoted._

inline def passThorugh(inline condition: Boolean): Any =
${ passThorughImpl('{condition}) }

def passThorughImpl(condition: Expr[Boolean])(using Quotes): Expr[Any] = condition
6 changes: 6 additions & 0 deletions tests/pos/i22974/main_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object Test {
def main(): Unit =
import pack.Maybe
val res: Maybe[Maybe[Int]] = ???
passThorugh(res.flatten.isDefined)
}
18 changes: 18 additions & 0 deletions tests/pos/i22974a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
object outer:
opaque type Queue = Queue.Unsafe
object Queue:
abstract class Unsafe
opaque type Unbounded = Queue
object Unbounded:
inline def initWith()(f: Unbounded => Unit): Unit =
f(Unsafe.init())

opaque type Unsafe <: Queue.Unsafe = Queue
object Unsafe:
def init[A](): Unsafe = ???

object Resource:
def run: Unit =
outer.Queue.Unbounded.initWith() { q =>
???
}
24 changes: 24 additions & 0 deletions tests/pos/i22974b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
object outer:
opaque type Queue = Queue.Unsafe
object Queue:
abstract class Unsafe
opaque type Unbounded = Queue
object Unbounded:
opaque type Unsafe <: Queue.Unsafe = Queue
object Unsafe:
def init[A](): Unsafe = ???

object Resource:
def run: Unit =
val $proxy2: outer.type{type Queue = outer.Queue.Unsafe} =
outer.asInstanceOf[outer.type{type Queue = outer.Queue.Unsafe}]
val $proxy1: $proxy2.Queue.type{type Unbounded = $proxy2.Queue} =
$proxy2.Queue.asInstanceOf[$proxy2.Queue.type{type Unbounded = $proxy2.Queue}]
val $proxy3: $proxy1.Unbounded.type{type Unsafe = $proxy2.Queue} =
$proxy1.Unbounded.asInstanceOf[$proxy1.Unbounded.type{type Unsafe = $proxy2.Queue}]
val Unbounded$_this:
$proxy1.Unbounded.type{type Unsafe = $proxy2.Queue} = $proxy3
val f$proxy1: (outer.Queue.Unbounded => Unit) & ($proxy1.Unbounded => Unit) =
((q: outer.Queue.Unbounded) => ???).asInstanceOf[(outer.Queue.Unbounded => Unit) & ($proxy1.Unbounded => Unit)]

f$proxy1(Unbounded$_this.Unsafe.init())
18 changes: 18 additions & 0 deletions tests/pos/i22974c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
object other:
sealed abstract class Absent
case object Absent extends Absent
case class PresentAbsent(val depth: Int)
opaque type Present[+A] = A | PresentAbsent
opaque type Maybe[+A] >: (Absent | Present[A]) = Absent | Present[A]

extension [A](self: Maybe[A]) {
inline def flatten[B]: Maybe[B] = if self.isEmpty then Absent else ???
def isEmpty: Boolean = self.isInstanceOf[Absent]
}

class Test {
def main(): Unit =
import other.Maybe
val res: Maybe[Maybe[Int]] = ???
res.flatten
}
Loading