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