From d9aa755ed12427020ad5e31790defb488286bbde Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 24 Jun 2025 19:50:47 +0200 Subject: [PATCH 1/3] Fix regressions in asSeenFrom introduced in 3.7 The body of isLegalPrefix used to read: pre.isStable || !ctx.phase.isTyper but was changed to drop the second condition in #21954 (originally included in 3.6.4-RC1, reverted from 3.6.4 final but back in 3.7). This has led to a number of regressions, the last ones discussed in #23423. To make the testcases added in #21594 pass, this PR proposes a less drastic change: relax isLegalPrefix as before, unless we're doing an implicit search. This should dramatically reduce the possibility for regressions. Fixes #23423. Fixes #22676. [Cherry-picked 2e4bc0abb8a374d78fe1aac383f3208b5efb5eb1] --- .../src/dotty/tools/dotc/interactive/Completion.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala index de9fcb8f6cb4..dc683aabe1e6 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala @@ -324,15 +324,15 @@ object Completion: * 8. symbol is not a constructor proxy module when in type completion mode * 9. have same term/type kind as name prefix given so far */ - def isValidCompletionSymbol(sym: Symbol, completionMode: Mode, isNew: Boolean)(using Context): Boolean = - + def isValidCompletionSymbol(sym: Symbol, completionMode: Mode, isNew: Boolean)(using Context): Boolean = try lazy val isEnum = sym.is(Enum) || (sym.companionClass.exists && sym.companionClass.is(Enum)) sym.exists && !sym.isAbsent(canForce = false) && !sym.isPrimaryConstructor && - sym.sourceSymbol.exists && + // running sourceSymbol on ExportedTerm will force a lot of computation from collectSubTrees + (sym.is(ExportedTerm) || sym.sourceSymbol.exists) && (!sym.is(Package) || sym.is(ModuleClass)) && !sym.isAllOf(Mutable | Accessor) && !sym.isPackageObject && @@ -343,6 +343,9 @@ object Completion: (completionMode.is(Mode.Term) && (sym.isTerm || sym.is(ModuleClass)) || (completionMode.is(Mode.Type) && (sym.isType || sym.isStableMember))) ) + catch + case NonFatal(ex) => + false end isValidCompletionSymbol given ScopeOrdering(using Context): Ordering[Seq[SingleDenotation]] with From 14bc3a4e4acd4d979dc527f77017b2ee33d5ecf0 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Wed, 2 Jul 2025 16:38:18 +0200 Subject: [PATCH 2/3] Fix stale top level synthetic package object being used in later runs [Cherry-picked c3e14438fdf7e9675a8a433cf004c0884f2e9dca] --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- tests/pos-macros/i13821-a/Macro.scala | 6 ++++++ tests/pos-macros/i13821-a/Test.scala | 12 ++++++++++++ tests/pos-macros/i13821-b/Macro.scala | 7 +++++++ tests/pos-macros/i13821-b/Test.scala | 14 ++++++++++++++ 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/pos-macros/i13821-a/Macro.scala create mode 100644 tests/pos-macros/i13821-a/Test.scala create mode 100644 tests/pos-macros/i13821-b/Macro.scala create mode 100644 tests/pos-macros/i13821-b/Test.scala diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index bd43578e3d53..c39db64b77cf 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -2720,7 +2720,7 @@ object SymDenotations { || owner.isRefinementClass || owner.is(Scala2x) || owner.unforcedDecls.contains(denot.name, denot.symbol) - || (denot.is(Synthetic) && denot.is(ModuleClass) && stillValidInOwner(denot.companionClass)) + || (denot.is(Synthetic) && denot.is(ModuleClass) && denot.companionClass.exists && stillValidInOwner(denot.companionClass)) || denot.isSelfSym || denot.isLocalDummy) catch case ex: StaleSymbol => false diff --git a/tests/pos-macros/i13821-a/Macro.scala b/tests/pos-macros/i13821-a/Macro.scala new file mode 100644 index 000000000000..3583a44ffddc --- /dev/null +++ b/tests/pos-macros/i13821-a/Macro.scala @@ -0,0 +1,6 @@ +trait Conversions: + given conv(using DFBits.Candidate): Conversion[Int, DFVal] = ??? + +import scala.quoted.* +transparent inline def f: Short = ${ getWidthMacro } +private def getWidthMacro(using Quotes): Expr[Short] = '{ ??? } diff --git a/tests/pos-macros/i13821-a/Test.scala b/tests/pos-macros/i13821-a/Test.scala new file mode 100644 index 000000000000..86f5a6289a80 --- /dev/null +++ b/tests/pos-macros/i13821-a/Test.scala @@ -0,0 +1,12 @@ +type DFBits = Long +object DFBits: + def a: Unit = f // forces suspension of this compilation unit in typer + def b: DFVal = 2 // uses implicit conversion `DFVal.conv` + + trait Candidate + object Candidate: + given candidate: Candidate = ??? // completed in run 3 but created in run 2 +end DFBits + +trait DFVal +object DFVal extends Conversions diff --git a/tests/pos-macros/i13821-b/Macro.scala b/tests/pos-macros/i13821-b/Macro.scala new file mode 100644 index 000000000000..c1c9c5e17851 --- /dev/null +++ b/tests/pos-macros/i13821-b/Macro.scala @@ -0,0 +1,7 @@ +import outer._ +trait Conversions: + given conv(using DFBits.Candidate): Conversion[Int, DFVal] = ??? + +import scala.quoted.* +transparent inline def f: Short = ${ getWidthMacro } +private def getWidthMacro(using Quotes): Expr[Short] = '{ ??? } diff --git a/tests/pos-macros/i13821-b/Test.scala b/tests/pos-macros/i13821-b/Test.scala new file mode 100644 index 000000000000..5c9b8755a33c --- /dev/null +++ b/tests/pos-macros/i13821-b/Test.scala @@ -0,0 +1,14 @@ +type outer = Int +object outer: + type DFBits = Long + object DFBits: + def a: Unit = f // forces suspension of this compilation unit in typer + def b: DFVal = 2 // uses implicit conversion `DFVal.conv` + + trait Candidate + object Candidate: + given candidate: Candidate = ??? // completed in run 3 but created in run 2 + end DFBits + + trait DFVal + object DFVal extends Conversions From 2d32188eb35f7080bdfada598076429f6f2e37f2 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Thu, 3 Jul 2025 13:33:20 +0200 Subject: [PATCH 3/3] Move previously-failing-now-compiling tests to pos tests They were previously fixed from crashing to erroring state, now compiling. The cause of the previous crashes looks the same as the one fixes in this PR, where the stale synthetic top level package object would be brought forward, causing other stale symbols to be used. [Cherry-picked 08b8340073a8286a82fb48543512d672c78aefc3] --- tests/neg/i19351.check | 4 ---- tests/neg/i19351/A.scala | 5 ----- tests/neg/i19351a.check | 4 ---- tests/pos-macros/i19351/A.scala | 6 ++++++ tests/{neg => pos-macros}/i19351/B.scala | 2 +- tests/{neg => pos-macros}/i19351a/Macro.scala | 0 tests/{neg => pos-macros}/i19351a/Test.scala | 2 +- 7 files changed, 8 insertions(+), 15 deletions(-) delete mode 100644 tests/neg/i19351.check delete mode 100644 tests/neg/i19351/A.scala delete mode 100644 tests/neg/i19351a.check create mode 100644 tests/pos-macros/i19351/A.scala rename tests/{neg => pos-macros}/i19351/B.scala (84%) rename tests/{neg => pos-macros}/i19351a/Macro.scala (100%) rename tests/{neg => pos-macros}/i19351a/Test.scala (87%) diff --git a/tests/neg/i19351.check b/tests/neg/i19351.check deleted file mode 100644 index a9ee10510b32..000000000000 --- a/tests/neg/i19351.check +++ /dev/null @@ -1,4 +0,0 @@ --- Error: tests/neg/i19351/A.scala:3:35 -------------------------------------------------------------------------------- -3 | inline def myMacro(): x.type = ${myMacroExpr} // error - | ^ - |Cyclic macro dependency; macro refers to a toplevel symbol in tests/neg/i19351/A.scala from which the macro is called diff --git a/tests/neg/i19351/A.scala b/tests/neg/i19351/A.scala deleted file mode 100644 index f2258631a15a..000000000000 --- a/tests/neg/i19351/A.scala +++ /dev/null @@ -1,5 +0,0 @@ -//object A: - val x: Int = 1 - inline def myMacro(): x.type = ${myMacroExpr} // error - def test = myMacro() - diff --git a/tests/neg/i19351a.check b/tests/neg/i19351a.check deleted file mode 100644 index 10789c2db5aa..000000000000 --- a/tests/neg/i19351a.check +++ /dev/null @@ -1,4 +0,0 @@ --- Error: tests/neg/i19351a/Test.scala:8:34 ---------------------------------------------------------------------------- -8 |inline def not(b: Bool): Bool = ${notMacro('b)} // error - | ^ - |Cyclic macro dependency; macro refers to a toplevel symbol in tests/neg/i19351a/Test.scala from which the macro is called diff --git a/tests/pos-macros/i19351/A.scala b/tests/pos-macros/i19351/A.scala new file mode 100644 index 000000000000..0b2c7acc3797 --- /dev/null +++ b/tests/pos-macros/i19351/A.scala @@ -0,0 +1,6 @@ +// object A: + val x: Int = 1 + inline def myMacro(): x.type = ${myMacroExpr} + def test = myMacro() + +@main def main() = () \ No newline at end of file diff --git a/tests/neg/i19351/B.scala b/tests/pos-macros/i19351/B.scala similarity index 84% rename from tests/neg/i19351/B.scala rename to tests/pos-macros/i19351/B.scala index 8c8c071f3607..a22b4d5c51b6 100644 --- a/tests/neg/i19351/B.scala +++ b/tests/pos-macros/i19351/B.scala @@ -1,3 +1,3 @@ import scala.quoted.* -//import A.* +// import A.* def myMacroExpr(using Quotes): Expr[x.type] = '{???} \ No newline at end of file diff --git a/tests/neg/i19351a/Macro.scala b/tests/pos-macros/i19351a/Macro.scala similarity index 100% rename from tests/neg/i19351a/Macro.scala rename to tests/pos-macros/i19351a/Macro.scala diff --git a/tests/neg/i19351a/Test.scala b/tests/pos-macros/i19351a/Test.scala similarity index 87% rename from tests/neg/i19351a/Test.scala rename to tests/pos-macros/i19351a/Test.scala index 84fb6ca4ae78..7f9e6dbc9786 100644 --- a/tests/neg/i19351a/Test.scala +++ b/tests/pos-macros/i19351a/Test.scala @@ -5,7 +5,7 @@ type Bool = [R] => (R, R) => R val True: Bool = [R] => (t: R, _: R) => t val False: Bool = [R] => (_: R, f: R) => f -inline def not(b: Bool): Bool = ${notMacro('b)} // error +inline def not(b: Bool): Bool = ${notMacro('b)} inline def show(b: Bool): String = ${showMacro('b)} //inline def not(b: Bool): Bool = ${foldMacro('b, 'False, 'True)} //inline def show(b: Bool): String = ${foldMacro('b, '{"TRUE"}, '{"FALSE"})}