Skip to content

Commit 7583dd6

Browse files
committed
Fix inline proxy generation for opaque types referencing other opaque types
1 parent 0f9e502 commit 7583dd6

File tree

4 files changed

+93
-2
lines changed

4 files changed

+93
-2
lines changed

Diff for: compiler/src/dotty/tools/dotc/inlines/Inliner.scala

+44-2
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,28 @@ object Inliner:
144144
else Nil
145145
case _ => Nil
146146
val refinements = openOpaqueAliases(cls.givenSelfType)
147+
148+
// Map references in the refinements from the proxied termRef
149+
// to the recursive type of the refined type
150+
// e.g.: Obj.type{type A = Obj.B; type B = Int} -> Obj.type{type A = <recthis>.B; type B = Int}
151+
def mapRecTermRefReferences(recType: RecType, refinedType: Type) =
152+
new TypeMap {
153+
def apply(tp: Type) = tp match
154+
case RefinedType(a: RefinedType, b, info) => RefinedType(apply(a), b, apply(info))
155+
case RefinedType(a, b, info) => RefinedType(a, b, apply(info))
156+
case TypeRef(prefix, des) => TypeRef(apply(prefix), des)
157+
case termRef: TermRef if termRef == ref => recType.recThis
158+
case _ => mapOver(tp)
159+
}.apply(refinedType)
160+
147161
val refinedType = refinements.foldLeft(ref: Type): (parent, refinement) =>
148162
RefinedType(parent, refinement._1, TypeAlias(refinement._2))
149-
val refiningSym = newSym(InlineBinderName.fresh(), Synthetic, refinedType, span)
163+
164+
val recType = RecType.closeOver ( recType =>
165+
mapRecTermRefReferences(recType, refinedType)
166+
)
167+
168+
val refiningSym = newSym(InlineBinderName.fresh(), Synthetic, recType, span)
150169
refiningSym.termRef
151170

152171
def unapply(refiningRef: TermRef)(using Context): Option[TermRef] =
@@ -387,7 +406,9 @@ class Inliner(val call: tpd.Tree)(using Context):
387406
val refiningRef = OpaqueProxy(ref, cls, call.span)
388407
val refiningSym = refiningRef.symbol.asTerm
389408
val refinedType = refiningRef.info
390-
val refiningDef = ValDef(refiningSym, tpd.ref(ref).cast(refinedType), inferred = true).withSpan(span)
409+
val refiningDef = addProxiesForRecurrentOpaques(
410+
ValDef(refiningSym, tpd.ref(ref).cast(refinedType), inferred = true).withSpan(span)
411+
)
391412
inlining.println(i"add opaque alias proxy $refiningDef for $ref in $tp")
392413
bindingsBuf += refiningDef
393414
opaqueProxies += ((ref, refiningSym.termRef))
@@ -407,6 +428,27 @@ class Inliner(val call: tpd.Tree)(using Context):
407428
}
408429
)
409430

431+
/** Transforms proxies that reference other opaque types, like for:
432+
* object Obj1 { opaque type A = Int }
433+
* object Obj2 { opaque type B = A }
434+
* and proxy$1 of type Obj2.type{type B = Obj1.A}
435+
* creates proxy$2 of type Obj1.type{type A = Int}
436+
* and transforms proxy$1 into Obj2.type{type B = proxy$2.A}
437+
*/
438+
private def addProxiesForRecurrentOpaques(binding: ValDef)(using Context): ValDef =
439+
def fixRefinedTypes(ref: Type): Unit =
440+
ref match
441+
case recType: RecType => fixRefinedTypes(recType.underlying)
442+
case RefinedType(parent, name, info) =>
443+
addOpaqueProxies(info.widen, binding.span, true)
444+
fixRefinedTypes(parent)
445+
case _ =>
446+
fixRefinedTypes(binding.symbol.info)
447+
binding.symbol.info = mapOpaques.typeMap(binding.symbol.info)
448+
mapOpaques.transform(binding).asInstanceOf[ValDef]
449+
.showing(i"transformed this binding exposing opaque aliases: $result", inlining)
450+
end addProxiesForRecurrentOpaques
451+
410452
/** If `binding` contains TermRefs that refer to objects with opaque
411453
* type aliases, add proxy definitions that expose these aliases
412454
* and substitute such TermRefs with theproxies. Example from pos/opaque-inline1.scala:

Diff for: tests/pos/22359a.scala

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
opaque type NT[N <: Tuple, V <: Tuple] = V
2+
opaque type System = NT[Tuple1["wires"], Tuple1[Any]]
3+
4+
extension [N <: Tuple, V <: Tuple] (x: NT[N, V]) {
5+
inline def apply(n: Int): Any =
6+
x.productElement(n)
7+
}
8+
9+
extension (system: System) {
10+
inline def foo =
11+
system.apply(0)
12+
}
13+
14+
val simulation: System = ???
15+
val _ = simulation.foo

Diff for: tests/pos/22359b.scala

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
object Obj2:
2+
opaque type NT[N <: Tuple, V <: Tuple] = V
3+
4+
extension [N <: Tuple, V <: Tuple] (x: NT[N, V]) {
5+
inline def apply(n: Int): Any =
6+
x.productElement(n)
7+
}
8+
9+
object Obj:
10+
opaque type System = Obj2.NT[Tuple1["wires"], Tuple1[Any]]
11+
12+
extension (system: System) {
13+
inline def foo = system.apply(0)
14+
}
15+
import Obj._
16+
val simulation: System = ???
17+
val _ = simulation.foo

Diff for: tests/pos/i17243.scala

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
object Opaque:
2+
opaque type A = Int
3+
4+
val va: A = 1
5+
6+
inline def a(x: A) =
7+
x + 1
8+
9+
object Opaque2:
10+
opaque type B = Opaque.A
11+
12+
val vb: B = Opaque.va
13+
14+
inline def b(x: B) = Opaque.a(x)
15+
16+
@main def Test() =
17+
print(Opaque2.b(Opaque2.vb))

0 commit comments

Comments
 (0)