Skip to content

Commit 854ef0a

Browse files
authored
Merge pull request scala#10831 from som-snytt/issue/13022-CCE-delambda-result
Improve result of bridge in delambdafy
2 parents c03e3c0 + 76d095f commit 854ef0a

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

src/compiler/scala/tools/nsc/transform/Delambdafy.scala

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
4343

4444
final case class LambdaMetaFactoryCapable(lambdaTarget: Symbol, arity: Int, functionalInterface: Symbol, sam: Symbol, bridges: List[Symbol], isSerializable: Boolean)
4545

46-
/**
47-
* Get the symbol of the target lifted lambda body method from a function. I.e. if
48-
* the function is {args => anonfun(args)} then this method returns anonfun's symbol
49-
*/
46+
/** Get the symbol of the target lifted lambda body method from a function. I.e. if
47+
* the function is {args => anonfun(args)} then this method returns anonfun's symbol
48+
*/
5049
private def targetMethod(fun: Function): Symbol = fun match {
5150
case Function(_, Apply(target, _)) => target.symbol
5251
case _ =>
@@ -177,9 +176,11 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
177176
val resTpOk = (
178177
samResultType =:= UnitTpe
179178
|| functionResultType =:= samResultType
180-
|| (isReferenceType(samResultType) && isReferenceType(functionResultType))) // yes, this is what the spec says -- no further correspondence required
181-
if (resTpOk && (samParamTypes corresponds functionParamTypes){ (samParamTp, funParamTp) =>
182-
funParamTp =:= samParamTp || (isReferenceType(funParamTp) && isReferenceType(samParamTp) && funParamTp <:< samParamTp) }) target
179+
|| (isReferenceType(samResultType) && isReferenceType(functionResultType))) // per spec, no further correspondence required
180+
def paramTpsOk = samParamTypes.corresponds(functionParamTypes)((samParamTp, funParamTp) =>
181+
funParamTp =:= samParamTp ||
182+
(isReferenceType(funParamTp) && isReferenceType(samParamTp) && funParamTp <:< samParamTp))
183+
if (resTpOk && paramTpsOk) target
183184
else {
184185
// We have to construct a new lambda target that bridges to the one created by uncurry.
185186
// The bridge must satisfy the above invariants, while also minimizing adaptation on our end.
@@ -194,7 +195,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
194195
// which means the function's parameter -- even if it expects a value class -- will need to be
195196
// boxed on the generic call to the sam method.
196197

197-
val bridgeParamTypes = map2(samParamTypes, functionParamTypes){ (samParamTp, funParamTp) =>
198+
val bridgeParamTypes = map2(samParamTypes, functionParamTypes) { (samParamTp, funParamTp) =>
198199
if (isReferenceType(samParamTp) && funParamTp <:< samParamTp) funParamTp
199200
else postErasure.elimErasedValueType(samParamTp)
200201
}
@@ -243,9 +244,12 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
243244

244245
gen.mkMethodCall(Select(gen.mkAttributedThis(oldClass), target), capturedArgRefs ::: functionArgRefs)
245246
}
247+
val forwarderResultType =
248+
if (samResultType.isInstanceOf[ErasedValueType] && functionResultType.isInstanceOf[ErasedValueType]) bridgeResultType
249+
else functionResultType
246250

247251
val bridge = postErasure.newTransformer(unit).transform(DefDef(methSym, List(bridgeParams.map(ValDef(_))),
248-
adaptToType(forwarderCall setType functionResultType, bridgeResultType))).asInstanceOf[DefDef]
252+
adaptToType(forwarderCall.setType(forwarderResultType), bridgeResultType))).asInstanceOf[DefDef]
249253

250254
boxingBridgeMethods += bridge
251255
bridge.symbol

test/files/run/t13022.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
case class StringValue(value: String) extends AnyVal
3+
4+
trait Foo[A] {
5+
def singleMethod(arg: A): StringValue
6+
}
7+
8+
class R {
9+
val foo1: Foo[Int] = new Foo[Int] {
10+
override def singleMethod(arg: Int): StringValue = new StringValue(arg.toString)
11+
}
12+
val foo2: Foo[Int] = (arg: Int) => new StringValue(arg.toString)
13+
val foo3 = (arg: Int) => new StringValue(arg.toString)
14+
15+
def run() = {
16+
assert(foo1.singleMethod(1).toString == "StringValue(1)")
17+
assert(foo2.singleMethod(1).toString == "StringValue(1)") // throws ClassCastException
18+
assert(foo3(1).toString == "StringValue(1)")
19+
}
20+
}
21+
object Test extends App {
22+
new R().run()
23+
}

0 commit comments

Comments
 (0)