diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 4381c9a2f52c..bab3992899f3 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -168,6 +168,13 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas /** A mapping from method types to the parameters used in constructing them */ private val paramsOfMethodType = new java.util.IdentityHashMap[MethodType, List[Symbol]] + /** Set of var param accessors that need to become case accessors */ + private val paramAccessorNeedsCaseAccessor = mutable.Map.empty[ClassSymbol, mutable.Set[Name]] + + /** If a var param accessors that need to become case accessors */ + private def paramAccessorNeedsCaseAccessor(owner: ClassSymbol, name: Name): Boolean = + paramAccessorNeedsCaseAccessor.get(owner).exists(_.contains(name)) + protected def errorBadSignature(msg: String, original: Option[RuntimeException] = None)(using Context): Nothing = { val ex = new BadSignature( i"""error reading Scala signature of $classRoot from $source: @@ -462,6 +469,14 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas flags &~= Method | Accessor if !flags.is(StableRealizable) then flags |= Mutable + // Skip case accessor `$access$` and keep track of their name to make `` the case accessor + if flags.is(CaseAccessor) && name.toString().contains("$access$") then + val accessorName = name.toString().split('$').head.toTermName + paramAccessorNeedsCaseAccessor + .getOrElseUpdate(owner.asClass, mutable.Set.empty) + .+=(accessorName) + return NoSymbol // skip this member + name = name.adjustIfModuleClass(flags) if (flags.is(Method)) name = @@ -632,6 +647,11 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas // This is the `def` of an accessor that needs to be transformed into // a `val`/`var`. Note that the `Method | Accessor` flags were already // striped away in `readDisambiguatedSymbol`. + // + // If there was a `$access$` case accessor, we also need to + // make this accessor a case accessor. + if paramAccessorNeedsCaseAccessor(denot.owner.asClass, denot.name) then + denot.setFlag(CaseAccessor) resultType case tp1 => tp1 denot.info = diff --git a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala index 84c7b916fa74..94d42952a6eb 100644 --- a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala @@ -1058,7 +1058,7 @@ class DottyBytecodeTests extends DottyBytecodeTest { TypeOp(CHECKCAST, "scala/collection/immutable/$colon$colon"), VarOp(ASTORE, 3), VarOp(ALOAD, 3), - Invoke(INVOKEVIRTUAL, "scala/collection/immutable/$colon$colon", "next$access$1", "()Lscala/collection/immutable/List;", false), + Invoke(INVOKEVIRTUAL, "scala/collection/immutable/$colon$colon", "next", "()Lscala/collection/immutable/List;", false), VarOp(ASTORE, 4), VarOp(ALOAD, 3), Invoke(INVOKEVIRTUAL, "scala/collection/immutable/$colon$colon", "head", "()Ljava/lang/Object;", false), @@ -1112,7 +1112,7 @@ class DottyBytecodeTests extends DottyBytecodeTest { Invoke(INVOKESTATIC, "scala/runtime/BoxesRunTime", "unboxToInt", "(Ljava/lang/Object;)I", false), VarOp(ISTORE, 4), VarOp(ALOAD, 3), - Invoke(INVOKEVIRTUAL, "scala/collection/immutable/$colon$colon", "next$access$1", "()Lscala/collection/immutable/List;", false), + Invoke(INVOKEVIRTUAL, "scala/collection/immutable/$colon$colon", "next", "()Lscala/collection/immutable/List;", false), VarOp(ASTORE, 5), Op(ICONST_1), VarOp(ILOAD, 4), diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 5d3c8f59a852..e93a0435987b 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -616,7 +616,7 @@ trait ParallelTesting extends RunnerOrchestration { self => def scala2Command(): Array[String] = { assert(!flags.options.contains("-scalajs"), - "Compilation tests with Scala.js on Scala 2 are not supported.\nThis test can be blacklisted in compiler/test/dotc/*-scala-js.blacklist") + "Compilation tests with Scala.js on Scala 2 are not supported.\nThis test can be skipped using the `// scalajs: --skip` tag") val stdlibClasspath = artifactClasspath("org.scala-lang", "scala-library") val scalacClasspath = artifactClasspath("org.scala-lang", "scala-compiler") val flagsArgs = flags diff --git a/tests/neg/i18884.scala b/tests/neg/i18884.scala new file mode 100644 index 000000000000..6ba17fde7f70 --- /dev/null +++ b/tests/neg/i18884.scala @@ -0,0 +1,2 @@ +def test(xs: ::[Int]): List[Int] = + xs.next$access$1 // error diff --git a/tests/run/i18884.check b/tests/run/i18884.check new file mode 100644 index 000000000000..e70c450a107a --- /dev/null +++ b/tests/run/i18884.check @@ -0,0 +1,4 @@ +Foo1(1) +Foo2(2, 3) +Foo3(4, 5) +Foo4(6, 7) diff --git a/tests/run/i18884/A_1_c2.13.12.scala b/tests/run/i18884/A_1_c2.13.12.scala new file mode 100644 index 000000000000..23a2bee52ba5 --- /dev/null +++ b/tests/run/i18884/A_1_c2.13.12.scala @@ -0,0 +1,10 @@ +// scalajs: --skip + +package lib + +case class Foo1(private[lib] var x: Int) {} +case class Foo2(private[lib] var x: Int, private[lib] var y: Int) +case class Foo3(private[lib] var x: Int, var y: Int) +case class Foo4(var x: Int, private[lib] var y: Int) { + val z: Int = x +} diff --git a/tests/run/i18884/B_2.scala b/tests/run/i18884/B_2.scala new file mode 100644 index 000000000000..5c775529b953 --- /dev/null +++ b/tests/run/i18884/B_2.scala @@ -0,0 +1,14 @@ +import lib.* + +@main def Test: Unit = + test(new Foo1(1)) + test(new Foo2(2, 3)) + test(new Foo3(4, 5)) + test(new Foo4(6, 7)) + +def test(any: Any): Unit = + any match + case Foo1(x) => println(s"Foo1($x)") + case Foo2(x, y) => println(s"Foo2($x, $y)") + case Foo3(x, y) => println(s"Foo3($x, $y)") + case Foo4(x, y) => println(s"Foo4($x, $y)") diff --git a/tests/run/typeclass-derivation3.check b/tests/run/typeclass-derivation3.check index 12bb24628b0c..34b8a6b81f7e 100644 --- a/tests/run/typeclass-derivation3.check +++ b/tests/run/typeclass-derivation3.check @@ -9,6 +9,6 @@ Cons(hd = Cons(hd = 11, tl = Cons(hd = 22, tl = Cons(hd = 33, tl = Nil))), tl = Cons(hd = Left(x = 1), tl = Cons(hd = Right(x = Pair(x = 2, y = 3)), tl = Nil)) Cons(hd = Left(x = 1), tl = Cons(hd = Right(x = Pair(x = 2, y = 3)), tl = Nil)) true -::(head = 1, next$access$1 = ::(head = 2, next$access$1 = ::(head = 3, next$access$1 = Nil()))) -::(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())) -::(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()))) +::(head = 1, next = ::(head = 2, next = ::(head = 3, next = Nil()))) +::(head = ::(head = 1, next = Nil()), next = ::(head = ::(head = 2, next = ::(head = 3, next = Nil())), next = Nil())) +::(head = Nil(), next = ::(head = ::(head = 1, next = Nil()), next = ::(head = ::(head = 2, next = ::(head = 3, next = Nil())), next = Nil())))