Skip to content

Revert recent changes to opaque type proxy generation #23059

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

Merged
merged 3 commits into from
May 2, 2025
Merged
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
52 changes: 3 additions & 49 deletions compiler/src/dotty/tools/dotc/inlines/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -162,28 +162,9 @@ object Inliner:
else Nil
case _ => Nil
val refinements = openOpaqueAliases(cls.givenSelfType)

// Map references in the refinements from the proxied termRef
// to the recursive type of the refined type
// e.g.: Obj.type{type A = Obj.B; type B = Int} -> Obj.type{type A = <recthis>.B; type B = Int}
def mapRecTermRefReferences(recType: RecType, refinedType: Type) =
new TypeMap {
def apply(tp: Type) = tp match
case RefinedType(a: RefinedType, b, info) => RefinedType(apply(a), b, apply(info))
case RefinedType(a, b, info) => RefinedType(a, b, apply(info))
case TypeRef(prefix, des) => TypeRef(apply(prefix), des)
case termRef: TermRef if termRef == ref => recType.recThis
case _ => mapOver(tp)
}.apply(refinedType)

val refinedType = refinements.foldLeft(ref: Type): (parent, refinement) =>
RefinedType(parent, refinement._1, TypeAlias(refinement._2))

val recType = RecType.closeOver ( recType =>
mapRecTermRefReferences(recType, refinedType)
)

val refiningSym = newSym(InlineBinderName.fresh(), Synthetic, recType, span)
val refiningSym = newSym(InlineBinderName.fresh(), Synthetic, refinedType, span)
refiningSym.termRef

def unapply(refiningRef: TermRef)(using Context): Option[TermRef] =
Expand Down Expand Up @@ -402,9 +383,6 @@ class Inliner(val call: tpd.Tree)(using Context):
*/
private val opaqueProxies = new mutable.ListBuffer[(TermRef, TermRef)]

/** TermRefs for which we already started synthesising proxies */
private val visitedTermRefs = new mutable.HashSet[TermRef]

protected def hasOpaqueProxies = opaqueProxies.nonEmpty

/** Map first halves of opaqueProxies pairs to second halves, using =:= as equality */
Expand Down Expand Up @@ -432,15 +410,12 @@ class Inliner(val call: tpd.Tree)(using Context):
for cls <- ref.widen.baseClasses do
if cls.containsOpaques
&& (forThisProxy || inlinedMethod.isContainedIn(cls))
&& !visitedTermRefs.contains(ref)
&& mapRef(ref).isEmpty
then
visitedTermRefs += ref
val refiningRef = OpaqueProxy(ref, cls, call.span)
val refiningSym = refiningRef.symbol.asTerm
val refinedType = refiningRef.info
val refiningDef = addProxiesForRecurrentOpaques(
ValDef(refiningSym, tpd.ref(ref).cast(refinedType), inferred = true).withSpan(span)
)
val refiningDef = ValDef(refiningSym, tpd.ref(ref).cast(refinedType), inferred = true).withSpan(span)
inlining.println(i"add opaque alias proxy $refiningDef for $ref in $tp")
bindingsBuf += refiningDef
opaqueProxies += ((ref, refiningSym.termRef))
Expand All @@ -460,27 +435,6 @@ class Inliner(val call: tpd.Tree)(using Context):
}
)

/** Transforms proxies that reference other opaque types, like for:
* object Obj1 { opaque type A = Int }
* object Obj2 { opaque type B = A }
* and proxy$1 of type Obj2.type{type B = Obj1.A}
* creates proxy$2 of type Obj1.type{type A = Int}
* and transforms proxy$1 into Obj2.type{type B = proxy$2.A}
*/
private def addProxiesForRecurrentOpaques(binding: ValDef)(using Context): ValDef =
def fixRefinedTypes(ref: Type): Unit =
ref match
case recType: RecType => fixRefinedTypes(recType.underlying)
case RefinedType(parent, name, info) =>
addOpaqueProxies(info.widen, binding.span, true)
fixRefinedTypes(parent)
case _ =>
fixRefinedTypes(binding.symbol.info)
binding.symbol.info = mapOpaques.typeMap(binding.symbol.info)
mapOpaques.transform(binding).asInstanceOf[ValDef]
.showing(i"transformed this binding exposing opaque aliases: $result", inlining)
end addProxiesForRecurrentOpaques

/** If `binding` contains TermRefs that refer to objects with opaque
* type aliases, add proxy definitions that expose these aliases
* and substitute such TermRefs with theproxies. Example from pos/opaque-inline1.scala:
Expand Down
15 changes: 0 additions & 15 deletions tests/pos/22359a.scala

This file was deleted.

17 changes: 0 additions & 17 deletions tests/pos/22359b.scala

This file was deleted.

17 changes: 0 additions & 17 deletions tests/pos/i17243.scala

This file was deleted.

14 changes: 14 additions & 0 deletions tests/pos/i22974a/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/i22974a/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/i22974a/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/i22974b.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 =>
???
}
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