From d5cb84f222e1254a0a6b1d53a5461e9f1de19f41 Mon Sep 17 00:00:00 2001 From: odersky Date: Thu, 19 May 2022 17:29:04 +0200 Subject: [PATCH] Re-establish missing symbol from previous phase (in one specific case) Fixes #15158 --- .../dotty/tools/dotc/transform/Erasure.scala | 14 +++++- .../test/dotc/pos-test-pickling.blacklist | 1 + tests/pos/i15158.scala | 43 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i15158.scala diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index c7ae41912638..241e18e67880 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -695,7 +695,19 @@ object Erasure { return tree.asInstanceOf[Tree] // we are re-typing a primitive array op val owner = mapOwner(origSym) - val sym = if (owner eq origSym.maybeOwner) origSym else owner.info.decl(tree.name).symbol + var sym = if (owner eq origSym.maybeOwner) origSym else owner.info.decl(tree.name).symbol + if !sym.exists then + // We fail the sym.exists test for pos/i15158.scala, where we pass an infinitely + // recurring match type to an overloaded constructor. An equivalent test + // with regular apply methods succeeds. It's at present unclear whether + // - the program should be rejected, or + // - there is another fix. + // Therefore, we apply the fix to use the pre-erasure symbol, but only + // for constructors, in order not to mask other possible bugs that would + // trigger the assert(sym.exists, ...) below. + val prevSym = tree.symbol(using preErasureCtx) + if prevSym.isConstructor then sym = prevSym + assert(sym.exists, i"no owner from $owner/${origSym.showLocated} in $tree") if owner == defn.ObjectClass then checkValue(qual1) diff --git a/compiler/test/dotc/pos-test-pickling.blacklist b/compiler/test/dotc/pos-test-pickling.blacklist index 0b8b63701efe..e31b370d5b90 100644 --- a/compiler/test/dotc/pos-test-pickling.blacklist +++ b/compiler/test/dotc/pos-test-pickling.blacklist @@ -42,6 +42,7 @@ i9999.scala 13491.scala 7512.scala i6505.scala +i15158.scala # Opaque type i5720.scala diff --git a/tests/pos/i15158.scala b/tests/pos/i15158.scala new file mode 100644 index 000000000000..431430680954 --- /dev/null +++ b/tests/pos/i15158.scala @@ -0,0 +1,43 @@ +class Opt[T] + +class Buf[A](elts: Any, sz: Int): + def this(n: Int) = this(???, n) + +object Buf: + def apply[A](elts: Any, sz: Int): Buf[A] = new Buf[A](elts, sz) + def apply[A](n: Int): Buf[A] = apply[A](???, n) + +inline def foo(testFun: Any): Unit = {} + +val x = foo { + type Rec[A] = A match + case String => Opt[Rec[String]] + + val arr = new Buf[Rec[String]](8) + val arr2 = Buf[Rec[String]](8) + val arr3 = Buf.apply[Rec[String]](8) +} + +import scala.collection.mutable + +// https://github.com/plokhotnyuk/jsoniter-scala/blob/74d6d557bf81e904d07d4b8fbead4e4cab700bea/jsoniter-scala-macros/shared/src/test/scala-3/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodeMakerNewTypeSpec.scala#L40-L148 +class Spec { + inline def in(testFun: => Any): Unit = { + val _ = testFun + } + + in { + type JsonPrimitive = String | Int + type Rec[JA[_], A] = A match { + case JsonPrimitive => JsonPrimitive | JA[Rec[JA, JsonPrimitive]] + case _ => A | JA[Rec[JA, A]] + } + + type Json = Rec[ + [A] =>> Seq[A], + JsonPrimitive + ] + + val arr = new mutable.ArrayBuffer[Json](8) + } +}