Skip to content

Commit

Permalink
Fix inline proxy generation for opaque types referencing other opaque…
Browse files Browse the repository at this point in the history
… types (#22381)

Fixes #22359
Fixes #17243
  • Loading branch information
jchyb authored Jan 20, 2025
1 parent a377c8a commit fe2e6e9
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 2 deletions.
46 changes: 44 additions & 2 deletions compiler/src/dotty/tools/dotc/inlines/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,28 @@ 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 refiningSym = newSym(InlineBinderName.fresh(), Synthetic, refinedType, span)

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

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

def unapply(refiningRef: TermRef)(using Context): Option[TermRef] =
Expand Down Expand Up @@ -387,7 +406,9 @@ class Inliner(val call: tpd.Tree)(using Context):
val refiningRef = OpaqueProxy(ref, cls, call.span)
val refiningSym = refiningRef.symbol.asTerm
val refinedType = refiningRef.info
val refiningDef = ValDef(refiningSym, tpd.ref(ref).cast(refinedType), inferred = true).withSpan(span)
val refiningDef = addProxiesForRecurrentOpaques(
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 @@ -407,6 +428,27 @@ 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: 15 additions & 0 deletions tests/pos/22359a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
opaque type NT[N <: Tuple, V <: Tuple] = V
opaque type System = NT[Tuple1["wires"], Tuple1[Any]]

extension [N <: Tuple, V <: Tuple] (x: NT[N, V]) {
inline def apply(n: Int): Any =
x.productElement(n)
}

extension (system: System) {
inline def foo =
system.apply(0)
}

val simulation: System = ???
val _ = simulation.foo
17 changes: 17 additions & 0 deletions tests/pos/22359b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
object Obj2:
opaque type NT[N <: Tuple, V <: Tuple] = V

extension [N <: Tuple, V <: Tuple] (x: NT[N, V]) {
inline def apply(n: Int): Any =
x.productElement(n)
}

object Obj:
opaque type System = Obj2.NT[Tuple1["wires"], Tuple1[Any]]

extension (system: System) {
inline def foo = system.apply(0)
}
import Obj._
val simulation: System = ???
val _ = simulation.foo
17 changes: 17 additions & 0 deletions tests/pos/i17243.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
object Opaque:
opaque type A = Int

val va: A = 1

inline def a(x: A) =
x + 1

object Opaque2:
opaque type B = Opaque.A

val vb: B = Opaque.va

inline def b(x: B) = Opaque.a(x)

@main def Test() =
print(Opaque2.b(Opaque2.vb))

0 comments on commit fe2e6e9

Please sign in to comment.