@@ -572,54 +572,85 @@ object Erasure {
572
572
super .typedDefDef(ddef1, sym)
573
573
}
574
574
575
- /** After erasure, we may have to replace the closure method by a bridge.
576
- * LambdaMetaFactory handles this automatically for most types, but we have
577
- * to deal with boxing and unboxing of value classes ourselves.
578
- */
579
575
override def typedClosure (tree : untpd.Closure , pt : Type )(implicit ctx : Context ) = {
580
576
val xxl = defn.isXXLFunctionClass(tree.typeOpt.typeSymbol)
581
577
var implClosure @ Closure (_, meth, _) = super .typedClosure(tree, pt)
582
578
if (xxl) implClosure = cpy.Closure (implClosure)(tpt = TypeTree (defn.FunctionXXLType ))
583
579
implClosure.tpe match {
584
580
case SAMType (sam) =>
585
- val implType = meth.tpe.widen
581
+ val implType = meth.tpe.widen. asInstanceOf [ MethodType ]
586
582
587
- val List ( implParamTypes) = implType.paramInfoss
583
+ val implParamTypes = implType.paramInfos
588
584
val List (samParamTypes) = sam.info.paramInfoss
589
585
val implResultType = implType.resultType
590
586
val samResultType = sam.info.resultType
591
587
592
- // Given a value class V with an underlying type U, the following code:
593
- // val f: Function1[V, V] = x => ...
594
- // results in the creation of a closure and a method:
595
- // def $anonfun(v1: V): V = ...
596
- // val f: Function1[V, V] = closure($anonfun)
597
- // After [[Erasure]] this method will look like:
598
- // def $anonfun(v1: ErasedValueType(V, U)): ErasedValueType(V, U) = ...
599
- // And after [[ElimErasedValueType]] it will look like:
600
- // def $anonfun(v1: U): U = ...
601
- // This method does not implement the SAM of Function1[V, V] anymore and
602
- // needs to be replaced by a bridge:
603
- // def $anonfun$2(v1: V): V = new V($anonfun(v1.underlying))
604
- // val f: Function1 = closure($anonfun$2)
605
- // In general, a bridge is needed when the signature of the closure method after
606
- // Erasure contains an ErasedValueType but the corresponding type in the functional
607
- // interface is not an ErasedValueType.
608
- val bridgeNeeded =
609
- (implResultType :: implParamTypes, samResultType :: samParamTypes).zipped.exists(
610
- (implType, samType) => implType.isErasedValueType && ! samType.isErasedValueType
611
- )
612
-
613
- if (bridgeNeeded) {
614
- val bridge = ctx.newSymbol(ctx.owner, nme.ANON_FUN , Flags .Synthetic | Flags .Method , sam.info)
615
- val bridgeCtx = ctx.withOwner(bridge)
616
- Closure (bridge, bridgeParamss => {
617
- implicit val ctx = bridgeCtx
618
-
619
- val List (bridgeParams) = bridgeParamss
620
- val rhs = Apply (meth, (bridgeParams, implParamTypes).zipped.map(adapt(_, _)))
621
- adapt(rhs, sam.info.resultType)
622
- })
588
+ // The following code:
589
+ //
590
+ // val f: Function1[Int, Any] = x => ...
591
+ //
592
+ // results in the creation of a closure and a method in the typer:
593
+ //
594
+ // def $anonfun(x: Int): Any = ...
595
+ // val f: Function1[Int, Any] = closure($anonfun)
596
+ //
597
+ // Notice that `$anonfun` takes a primitive as argument, but the single abstract method
598
+ // of `Function1` after erasure is:
599
+ //
600
+ // def apply(x: Object): Object
601
+ //
602
+ // which takes a reference as argument. Hence, some form of adaptation is required.
603
+ //
604
+ // If we do nothing, the LambdaMetaFactory bootstrap method will
605
+ // automatically do the adaptation. Unfortunately, the result does not
606
+ // implement the expected Scala semantics: null should be "unboxed" to
607
+ // the default value of the value class, but LMF will throw a
608
+ // NullPointerException instead. LMF is also not capable of doing
609
+ // adaptation for derived value classes.
610
+ //
611
+ // Thus, we need to replace the closure method by a bridge method that
612
+ // forwards to the original closure method with appropriate
613
+ // boxing/unboxing. For our example above, this would be:
614
+ //
615
+ // def $anonfun1(x: Object): Object = $anonfun(BoxesRunTime.unboxToInt(x))
616
+ // val f: Function1 = closure($anonfun1)
617
+ //
618
+ // In general, a bridge is needed when, after Erasure:
619
+ // - one of the parameter type of the closure method is a non-reference type,
620
+ // and the corresponding type in the SAM is a reference type
621
+ // - or the result type of the closure method is an erased value type
622
+ // and the result type in the SAM isn't
623
+ // However, the following exception exists: If the SAM is replaced by
624
+ // JFunction*mc* in [[FunctionalInterfaces]], no bridge is needed: the
625
+ // SAM contains default methods to handle adaptation
626
+ //
627
+ // See test cases lambda-*.scala and t8017/ for concrete examples.
628
+
629
+ def isReferenceType (tp : Type ) = ! tp.isPrimitiveValueType && ! tp.isErasedValueType
630
+
631
+ if (! defn.isSpecializableFunction(implClosure.tpe.widen.classSymbol.asClass, implParamTypes, implResultType)) {
632
+ val paramAdaptationNeeded =
633
+ (implParamTypes, samParamTypes).zipped.exists((implType, samType) =>
634
+ ! isReferenceType(implType) && isReferenceType(samType))
635
+ val resultAdaptationNeeded =
636
+ implResultType.isErasedValueType && ! samResultType.isErasedValueType
637
+
638
+ if (paramAdaptationNeeded || resultAdaptationNeeded) {
639
+ val bridgeType =
640
+ if (paramAdaptationNeeded) {
641
+ if (resultAdaptationNeeded) sam.info
642
+ else implType.derivedLambdaType(paramInfos = samParamTypes)
643
+ } else implType.derivedLambdaType(resType = samResultType)
644
+ val bridge = ctx.newSymbol(ctx.owner, nme.ANON_FUN , Flags .Synthetic | Flags .Method , bridgeType)
645
+ val bridgeCtx = ctx.withOwner(bridge)
646
+ Closure (bridge, bridgeParamss => {
647
+ implicit val ctx = bridgeCtx
648
+
649
+ val List (bridgeParams) = bridgeParamss
650
+ val rhs = Apply (meth, (bridgeParams, implParamTypes).zipped.map(adapt(_, _)))
651
+ adapt(rhs, bridgeType.resultType)
652
+ }, targetType = implClosure.tpt.tpe)
653
+ } else implClosure
623
654
} else implClosure
624
655
case _ =>
625
656
implClosure
0 commit comments