Skip to content

Commit e94faee

Browse files
committed
Merge pull request scala#3274 from retronym/ticket/8017
SI-8017 Value class awareness for -Ydelamdafy:method
2 parents fa20a1c + 6a4947c commit e94faee

File tree

4 files changed

+64
-2
lines changed

4 files changed

+64
-2
lines changed

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,19 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
340340
else (true, adaptToType(tree, expectedTpe))
341341
}
342342

343+
def adaptAndPostErase(tree: Tree, pt: Type): (Boolean, Tree) = {
344+
val (needsAdapt, adaptedTree) = adapt(tree, pt)
345+
val trans = postErasure.newTransformer(unit)
346+
val postErasedTree = trans.atOwner(currentOwner)(trans.transform(adaptedTree)) // SI-8017 elimnates ErasedValueTypes
347+
(needsAdapt, postErasedTree)
348+
}
349+
343350
enteringPhase(currentRun.posterasurePhase) {
351+
// e.g, in:
352+
// class C(val a: Int) extends AnyVal; (x: Int) => new C(x)
353+
//
354+
// This type is:
355+
// (x: Int)ErasedValueType(class C, Int)
344356
val liftedBodyDefTpe: MethodType = {
345357
val liftedBodySymbol = {
346358
val Apply(method, _) = originalFunction.body
@@ -349,8 +361,14 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
349361
liftedBodySymbol.info.asInstanceOf[MethodType]
350362
}
351363
val (paramNeedsAdaptation, adaptedParams) = (bridgeSyms zip liftedBodyDefTpe.params map {case (bridgeSym, param) => adapt(Ident(bridgeSym) setType bridgeSym.tpe, param.tpe)}).unzip
352-
val body = Apply(gen.mkAttributedSelect(gen.mkAttributedThis(newClass), applyMethod.symbol), adaptedParams) setType applyMethod.symbol.tpe.resultType
353-
val (needsReturnAdaptation, adaptedBody) = adapt(typer.typed(body), ObjectTpe)
364+
// SI-8017 Before, this code used `applyMethod.symbol.info.resultType`.
365+
// But that symbol doesn't have a type history that goes back before `delambdafy`,
366+
// so we just see a plain `Int`, rather than `ErasedValueType(C, Int)`.
367+
// This triggered primitive boxing, rather than value class boxing.
368+
val resTp = liftedBodyDefTpe.finalResultType
369+
val body = Apply(gen.mkAttributedSelect(gen.mkAttributedThis(newClass), applyMethod.symbol), adaptedParams) setType resTp
370+
val (needsReturnAdaptation, adaptedBody) = adaptAndPostErase(body, ObjectTpe)
371+
354372
val needsBridge = (paramNeedsAdaptation contains true) || needsReturnAdaptation
355373
if (needsBridge) {
356374
val methDef = DefDef(bridgeMethSym, List(bridgeParams), adaptedBody)

test/files/run/t8017.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Ydelambdafy:method
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
object Test {
2+
def testC {
3+
val f1 = (c: C) => c.value
4+
val f2 = (x: Int) => new C(x)
5+
val f3 = (c1: C) => (c2: C) => (c1, c2)
6+
val r1 = f2(2)
7+
val r2 = f2(2)
8+
val r3 = f3(r1)(r2)
9+
val result = f1(r3._2)
10+
assert(result == 2)
11+
}
12+
13+
def testD {
14+
val f1 = (c: D) => c.value
15+
val f2 = (x: String) => new D(x)
16+
val f3 = (c1: D) => (c2: D) => (c1, c2)
17+
val r1 = f2("2")
18+
val r2 = f2("2")
19+
val r3 = f3(r1)(r2)
20+
val result = f1(r3._2)
21+
assert(result == "2")
22+
}
23+
24+
def testE {
25+
val f1 = (c: E[Int]) => c.value
26+
val f2 = (x: Int) => new E(x)
27+
val f3 = (c1: E[Int]) => (c2: E[Int]) => (c1, c2)
28+
val r1 = f2(2)
29+
val r2 = f2(2)
30+
val r3 = f3(r1)(r2)
31+
val result = f1(r3._2)
32+
assert(result == 2)
33+
}
34+
35+
def main(args: Array[String]) {
36+
testC
37+
testD
38+
testE
39+
}
40+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class C(val value: Int) extends AnyVal
2+
class D(val value: String) extends AnyVal
3+
class E[A](val value: A) extends AnyVal

0 commit comments

Comments
 (0)