Skip to content

Commit 3d8c24d

Browse files
committed
Reinterpret xyz$access$i when unpickling from Scala 2
Fixes #18884
1 parent d9c84b9 commit 3d8c24d

File tree

7 files changed

+49
-5
lines changed

7 files changed

+49
-5
lines changed

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
168168
/** A mapping from method types to the parameters used in constructing them */
169169
private val paramsOfMethodType = new java.util.IdentityHashMap[MethodType, List[Symbol]]
170170

171+
/** Set of var param accessors that need to become case accessors */
172+
private val paramAccessorNeedsCaseAccessor = mutable.Set.empty[Name]
173+
171174
protected def errorBadSignature(msg: String, original: Option[RuntimeException] = None)(using Context): Nothing = {
172175
val ex = new BadSignature(
173176
i"""error reading Scala signature of $classRoot from $source:
@@ -462,6 +465,12 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
462465
flags &~= Method | Accessor
463466
if !flags.is(StableRealizable) then flags |= Mutable
464467

468+
// Skip case accessor `<xyz>$access$<idx>` and keep track of their name to make `<xyz>` the case accessor
469+
if flags.is(CaseAccessor) && name.toString().contains("$access$") then
470+
val accessorName = name.toString().split('$').head
471+
paramAccessorNeedsCaseAccessor += accessorName.toTermName
472+
return NoSymbol // skip this member
473+
465474
name = name.adjustIfModuleClass(flags)
466475
if (flags.is(Method))
467476
name =
@@ -632,6 +641,11 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
632641
// This is the `def` of an accessor that needs to be transformed into
633642
// a `val`/`var`. Note that the `Method | Accessor` flags were already
634643
// striped away in `readDisambiguatedSymbol`.
644+
//
645+
// If there was a `<xyz>$access$<idx>` case accessor, we also need to
646+
// make this accessor a case accessor.
647+
if paramAccessorNeedsCaseAccessor(denot.name) then
648+
denot.setFlag(CaseAccessor)
635649
resultType
636650
case tp1 => tp1
637651
denot.info =

compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,7 @@ class DottyBytecodeTests extends DottyBytecodeTest {
10581058
TypeOp(CHECKCAST, "scala/collection/immutable/$colon$colon"),
10591059
VarOp(ASTORE, 3),
10601060
VarOp(ALOAD, 3),
1061-
Invoke(INVOKEVIRTUAL, "scala/collection/immutable/$colon$colon", "next$access$1", "()Lscala/collection/immutable/List;", false),
1061+
Invoke(INVOKEVIRTUAL, "scala/collection/immutable/$colon$colon", "next", "()Lscala/collection/immutable/List;", false),
10621062
VarOp(ASTORE, 4),
10631063
VarOp(ALOAD, 3),
10641064
Invoke(INVOKEVIRTUAL, "scala/collection/immutable/$colon$colon", "head", "()Ljava/lang/Object;", false),
@@ -1112,7 +1112,7 @@ class DottyBytecodeTests extends DottyBytecodeTest {
11121112
Invoke(INVOKESTATIC, "scala/runtime/BoxesRunTime", "unboxToInt", "(Ljava/lang/Object;)I", false),
11131113
VarOp(ISTORE, 4),
11141114
VarOp(ALOAD, 3),
1115-
Invoke(INVOKEVIRTUAL, "scala/collection/immutable/$colon$colon", "next$access$1", "()Lscala/collection/immutable/List;", false),
1115+
Invoke(INVOKEVIRTUAL, "scala/collection/immutable/$colon$colon", "next", "()Lscala/collection/immutable/List;", false),
11161116
VarOp(ASTORE, 5),
11171117
Op(ICONST_1),
11181118
VarOp(ILOAD, 4),

tests/neg/i18884.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def test(xs: ::[Int]): List[Int] =
2+
xs.next$access$1 // error

tests/run/i18884.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Foo1(1)
2+
Foo2(2, 3)
3+
Foo3(4, 5)
4+
Foo4(6, 7)

tests/run/i18884/A_1_c2.13.12.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// scalajs: --skip
2+
3+
package lib
4+
5+
case class Foo1(private[lib] var x: Int) {}
6+
case class Foo2(private[lib] var x: Int, private[lib] var y: Int)
7+
case class Foo3(private[lib] var x: Int, var y: Int)
8+
case class Foo4(var x: Int, private[lib] var y: Int) {
9+
val z: Int = x
10+
}

tests/run/i18884/B_2.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import lib.*
2+
3+
@main def Test: Unit =
4+
test(new Foo1(1))
5+
test(new Foo2(2, 3))
6+
test(new Foo3(4, 5))
7+
test(new Foo4(6, 7))
8+
9+
def test(any: Any): Unit =
10+
any match
11+
case Foo1(x) => println(s"Foo1($x)")
12+
case Foo2(x, y) => println(s"Foo2($x, $y)")
13+
case Foo3(x, y) => println(s"Foo3($x, $y)")
14+
case Foo4(x, y) => println(s"Foo4($x, $y)")

tests/run/typeclass-derivation3.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ Cons(hd = Cons(hd = 11, tl = Cons(hd = 22, tl = Cons(hd = 33, tl = Nil))), tl =
99
Cons(hd = Left(x = 1), tl = Cons(hd = Right(x = Pair(x = 2, y = 3)), tl = Nil))
1010
Cons(hd = Left(x = 1), tl = Cons(hd = Right(x = Pair(x = 2, y = 3)), tl = Nil))
1111
true
12-
::(head = 1, next$access$1 = ::(head = 2, next$access$1 = ::(head = 3, next$access$1 = Nil())))
13-
::(head = ::(head = 1, next$access$1 = Nil()), next$access$1 = ::(head = ::(head = 2, next$access$1 = ::(head = 3, next$access$1 = Nil())), next$access$1 = Nil()))
14-
::(head = Nil(), next$access$1 = ::(head = ::(head = 1, next$access$1 = Nil()), next$access$1 = ::(head = ::(head = 2, next$access$1 = ::(head = 3, next$access$1 = Nil())), next$access$1 = Nil())))
12+
::(head = 1, next = ::(head = 2, next = ::(head = 3, next = Nil())))
13+
::(head = ::(head = 1, next = Nil()), next = ::(head = ::(head = 2, next = ::(head = 3, next = Nil())), next = Nil()))
14+
::(head = Nil(), next = ::(head = ::(head = 1, next = Nil()), next = ::(head = ::(head = 2, next = ::(head = 3, next = Nil())), next = Nil())))

0 commit comments

Comments
 (0)