From 074f313f8907351d5be33e3cf6f22aa7df8adb71 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 21 Nov 2022 23:33:09 +0000 Subject: [PATCH] Fix REPL shadowing bug --- .../tools/dotc/printing/RefinedPrinter.scala | 2 +- .../src/dotty/tools/dotc/typer/Typer.scala | 6 ++++-- .../src/dotty/tools/repl/ReplCompiler.scala | 1 - .../tools/repl/ShadowingBatchTests.scala | 14 ++++++++++++++ .../dotty/tools/repl/ShadowingTests.scala | 19 ++++++++++++++++++- 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 62e1cd5baec8..568f7e271af6 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -1060,7 +1060,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (sym.isImport) sym.infoOrCompleter match { case info: Namer#Completer => return info.original.show - case info: ImportType => return s"import $info.expr.show" + case info: ImportType => return s"import ${info.expr.show}" case _ => } def name = diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 032bed38482c..6d02c878efde 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -439,7 +439,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer if (curImport.nn.unimported ne NoSymbol) unimported += curImport.nn.unimported if (curOwner.is(Package) && curImport != null && curImport.isRootImport && previous.exists) previous // no more conflicts possible in this case - else if (isPossibleImport(NamedImport) && (curImport nen outer.importInfo)) { + else if isPossibleImport(NamedImport) && + ((curImport nen outer.importInfo) + || curImport != null && !curImport.importSym.isCompleting && curImport.site.termSymbol.name.isReplWrapperName) + then val namedImp = namedImportRef(curImport.uncheckedNN) if (namedImp.exists) recurAndCheckNewOrShadowed(namedImp, NamedImport, ctx)(using outer) @@ -456,7 +459,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer updateUnimported() loop(ctx)(using outer) } - } else loop(ctx)(using outer) } } diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 8db288f50aca..69bd97148d73 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -62,7 +62,6 @@ class ReplCompiler extends Compiler: } val rootCtx = super.rootContext.fresh - .setOwner(defn.EmptyPackageClass) .withRootImports (state.validObjectIndexes).foldLeft(rootCtx)((ctx, id) => importPreviousRun(id)(using ctx)) diff --git a/compiler/test/dotty/tools/repl/ShadowingBatchTests.scala b/compiler/test/dotty/tools/repl/ShadowingBatchTests.scala index 5a96976bd867..7272c10aa003 100644 --- a/compiler/test/dotty/tools/repl/ShadowingBatchTests.scala +++ b/compiler/test/dotty/tools/repl/ShadowingBatchTests.scala @@ -32,6 +32,20 @@ class ShadowingBatchTests extends ErrorMessagesTest: ictx.setSetting(classpath, classpath.value + File.pathSeparator + dir.jpath.toAbsolutePath) } + @Test def io = + val lib = """|package io.foo + | + |object Bar { + | def baz: Int = 42 + |} + |""".stripMargin + val app = """|object Main: + | def main(args: Array[String]): Unit = + | println(io.foo.Bar.baz) + |""".stripMargin + checkMessages(lib).expectNoErrors + checkMessages(app).expectNoErrors + @Test def file = checkMessages("class C(val c: Int)").expectNoErrors checkMessages("object rsline1 {\n def line1 = new C().c\n}").expect { (_, msgs) => diff --git a/compiler/test/dotty/tools/repl/ShadowingTests.scala b/compiler/test/dotty/tools/repl/ShadowingTests.scala index 457819966346..ac1538f6d712 100644 --- a/compiler/test/dotty/tools/repl/ShadowingTests.scala +++ b/compiler/test/dotty/tools/repl/ShadowingTests.scala @@ -76,6 +76,18 @@ class ShadowingTests extends ReplTest(options = ShadowingTests.options): Files.delete(file) end compileShadowed + @Test def io = shadowedScriptedTest(name = "io", + shadowed = """|package io.foo + | + |object Bar { + | def baz: Int = 42 + |} + |""".stripMargin, + script = """|scala> io.foo.Bar.baz + |val res0: Int = 42 + |""".stripMargin + ) + @Test def i7635 = shadowedScriptedTest(name = "", shadowed = "class C(val c: Int)", script = @@ -97,7 +109,7 @@ class ShadowingTests extends ReplTest(options = ShadowingTests.options): |""".stripMargin ) - @Test def `shadow subdirectories on classpath` = + @Test def shadowSubDir = // NB: Tests of shadowing of subdirectories on the classpath are only valid // when the subdirectories exist prior to initialization of the REPL driver. // In the tests below this is enforced by the call to `testScript` which @@ -129,6 +141,11 @@ class ShadowingTests extends ReplTest(options = ShadowingTests.options): ShadowingTests.createSubDir("util") testScript(name = "", """|scala> import util.Try + |-- [E008] Not Found Error: ----------------------------------------------------- + |1 | import util.Try + | | ^^^ + | | value Try is not a member of util + |1 error found | |scala> object util { class Try { override def toString = "you've gotta try!" } } |// defined object util