@@ -409,7 +409,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
409
409
410
410
private val methPart = funPart(call)
411
411
private val callTypeArgs = typeArgss(call).flatten
412
- private val callValueArgss = termArgss(call)
412
+ private val rawCallValueArgss = termArgss(call)
413
413
private val inlinedMethod = methPart.symbol
414
414
private val inlineCallPrefix =
415
415
qualifier(methPart).orElse(This (inlinedMethod.enclosingClass.asClass))
@@ -581,31 +581,17 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
581
581
case (from, to) if from.symbol == ref.symbol && from =:= ref => to
582
582
}
583
583
584
- /** If `binding` contains TermRefs that refer to objects with opaque
585
- * type aliases, add proxy definitions that expose these aliases
586
- * and substitute such TermRefs with theproxies. Example from pos/opaque-inline1.scala:
587
- *
588
- * object refined:
589
- * opaque type Positive = Int
590
- * inline def Positive(value: Int): Positive = f(value)
591
- * def f(x: Positive): Positive = x
592
- * def run: Unit = { val x = 9; val nine = refined.Positive(x) }
593
- *
594
- * This generates the following proxies:
595
- *
596
- * val $proxy1: refined.type{type Positive = Int} =
597
- * refined.$asInstanceOf$[refined.type{type Positive = Int}]
598
- * val refined$_this: ($proxy1 : refined.type{Positive = Int}) =
599
- * $proxy1
600
- *
601
- * and every reference to `refined` in the inlined expression is replaced by
602
- * `refined_$this`.
584
+ /** If `tp` contains TermRefs that refer to objects with opaque
585
+ * type aliases, add proxy definitions to `opaqueProxies` that expose these aliases.
603
586
*/
604
- def accountForOpaques ( binding : ValDef )(using Context ): ValDef =
605
- binding.symbol.info .foreachPart {
587
+ def addOpaqueProxies ( tp : Type , span : Span , forThisProxy : Boolean )(using Context ): Unit =
588
+ tp .foreachPart {
606
589
case ref : TermRef =>
607
590
for cls <- ref.widen.classSymbols do
608
- if cls.containsOpaques && mapRef(ref).isEmpty then
591
+ if cls.containsOpaques
592
+ && (forThisProxy || inlinedMethod.isContainedIn(cls))
593
+ && mapRef(ref).isEmpty
594
+ then
609
595
def openOpaqueAliases (selfType : Type ): List [(Name , Type )] = selfType match
610
596
case RefinedType (parent, rname, TypeAlias (alias)) =>
611
597
val opaq = cls.info.member(rname).symbol
@@ -620,27 +606,67 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
620
606
RefinedType (parent, refinement._1, TypeAlias (refinement._2))
621
607
)
622
608
val refiningSym = newSym(InlineBinderName .fresh(), Synthetic , refinedType).asTerm
623
- val refiningDef = ValDef (refiningSym, tpd.ref(ref).cast(refinedType)).withSpan(binding. span)
624
- inlining.println(i " add opaque alias proxy $refiningDef" )
609
+ val refiningDef = ValDef (refiningSym, tpd.ref(ref).cast(refinedType)).withSpan(span)
610
+ inlining.println(i " add opaque alias proxy $refiningDef for $ref in $tp " )
625
611
bindingsBuf += refiningDef
626
612
opaqueProxies += ((ref, refiningSym.termRef))
627
613
case _ =>
628
614
}
615
+
616
+ /** Map all TermRefs that match left element in `opaqueProxies` to the
617
+ * corresponding right element.
618
+ */
619
+ val mapOpaques = TreeTypeMap (
620
+ typeMap = new TypeMap :
621
+ override def stopAt = StopAt .Package
622
+ def apply (t : Type ) = mapOver {
623
+ t match
624
+ case ref : TermRef => mapRef(ref).getOrElse(ref)
625
+ case _ => t
626
+ }
627
+ )
628
+
629
+ /** If `binding` contains TermRefs that refer to objects with opaque
630
+ * type aliases, add proxy definitions that expose these aliases
631
+ * and substitute such TermRefs with theproxies. Example from pos/opaque-inline1.scala:
632
+ *
633
+ * object refined:
634
+ * opaque type Positive = Int
635
+ * inline def Positive(value: Int): Positive = f(value)
636
+ * def f(x: Positive): Positive = x
637
+ * def run: Unit = { val x = 9; val nine = refined.Positive(x) }
638
+ *
639
+ * This generates the following proxies:
640
+ *
641
+ * val $proxy1: refined.type{type Positive = Int} =
642
+ * refined.$asInstanceOf$[refined.type{type Positive = Int}]
643
+ * val refined$_this: ($proxy1 : refined.type{Positive = Int}) =
644
+ * $proxy1
645
+ *
646
+ * and every reference to `refined` in the inlined expression is replaced by
647
+ * `refined_$this`.
648
+ */
649
+ def accountForOpaques (binding : ValDef )(using Context ): ValDef =
650
+ addOpaqueProxies(binding.symbol.info, binding.span, forThisProxy = true )
629
651
if opaqueProxies.isEmpty then binding
630
652
else
631
- val mapType = new TypeMap :
632
- override def stopAt = StopAt .Package
633
- def apply (t : Type ) = mapOver {
634
- t match
635
- case ref : TermRef => mapRef(ref).getOrElse(ref)
636
- case _ => t
637
- }
638
- binding.symbol.info = mapType(binding.symbol.info)
639
- val mapTree = TreeTypeMap (typeMap = mapType)
640
- mapTree.transform(binding).asInstanceOf [ValDef ]
653
+ binding.symbol.info = mapOpaques.typeMap(binding.symbol.info)
654
+ mapOpaques.transform(binding).asInstanceOf [ValDef ]
641
655
.showing(i " transformed this binding exposing opaque aliases: $result" , inlining)
642
656
end accountForOpaques
643
657
658
+ /** If value argument contains references to objects that contain opaque types,
659
+ * map them to their opaque proxies.
660
+ */
661
+ def mapOpaquesInValueArg (arg : Tree )(using Context ): Tree =
662
+ val argType = arg.tpe.widen
663
+ addOpaqueProxies(argType, arg.span, forThisProxy = false )
664
+ if opaqueProxies.nonEmpty then
665
+ val mappedType = mapOpaques.typeMap(argType)
666
+ if mappedType ne argType then arg.cast(AndType (arg.tpe, mappedType))
667
+ else arg
668
+ else arg
669
+
644
670
private def canElideThis (tpe : ThisType ): Boolean =
645
671
inlineCallPrefix.tpe == tpe && ctx.owner.isContainedIn(tpe.cls)
646
672
|| tpe.cls.isContainedIn(inlinedMethod)
@@ -773,7 +799,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
773
799
def inlined (sourcePos : SrcPos ): Tree = {
774
800
775
801
// Special handling of `requireConst` and `codeOf`
776
- callValueArgss match
802
+ rawCallValueArgss match
777
803
case (arg :: Nil ) :: Nil =>
778
804
if inlinedMethod == defn.Compiletime_requireConst then
779
805
arg match
@@ -823,6 +849,11 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
823
849
case TypeApply (fn, _) => paramTypess(fn, acc)
824
850
case _ => acc
825
851
852
+ val callValueArgss = rawCallValueArgss.nestedMapConserve(mapOpaquesInValueArg)
853
+
854
+ if callValueArgss ne rawCallValueArgss then
855
+ inlining.println(i " mapped value args = ${callValueArgss.flatten}%, % " )
856
+
826
857
// Compute bindings for all parameters, appending them to bindingsBuf
827
858
if ! computeParamBindings(inlinedMethod.info, callTypeArgs, callValueArgss, paramTypess(call, Nil )) then
828
859
return call
@@ -1254,7 +1285,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
1254
1285
case fail : Implicits .SearchFailureType =>
1255
1286
false
1256
1287
case _ =>
1257
- // inliner .println(i"inferred implicit $sym: ${sym.info} with $evidence: ${evidence.tpe.widen}, ${evCtx.gadt.constraint}, ${evCtx.typerState.constraint}")
1288
+ // inlining .println(i"inferred implicit $sym: ${sym.info} with $evidence: ${evidence.tpe.widen}, ${evCtx.gadt.constraint}, ${evCtx.typerState.constraint}")
1258
1289
newTermBinding(sym, evidence)
1259
1290
true
1260
1291
}
0 commit comments