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