From 6990aabb7c94076054dfe00ab9f7283fcc8481aa Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Tue, 21 Jul 2020 22:23:17 +0200 Subject: [PATCH] Fix #7312: choose root imports based on the source file Instead of setting the scala root imports in the rootContext, set them later and choose the right imports depending on the language (java or scala). --- compiler/src/dotty/tools/dotc/Run.scala | 20 +++--- .../dotty/tools/dotc/core/Definitions.scala | 61 ++++++++++++++----- .../src/dotty/tools/dotc/core/Phases.scala | 3 +- .../tools/dotc/parsing/JavaParsers.scala | 2 +- .../tools/dotc/printing/PlainPrinter.scala | 2 +- .../tools/dotc/transform/patmat/Space.scala | 2 +- .../src/dotty/tools/dotc/typer/FrontEnd.scala | 7 ++- .../dotty/tools/dotc/typer/ImportInfo.scala | 36 ++++++----- .../tools/dotc/typer/ImportSuggestions.scala | 2 +- .../src/dotty/tools/repl/ReplCompiler.scala | 16 +++-- .../src/dotty/tools/repl/ReplFrontEnd.scala | 7 ++- tests/run/java-no-scala-import/Config.java | 25 ++++++++ tests/run/java-no-scala-import/Test.scala | 6 ++ 13 files changed, 133 insertions(+), 56 deletions(-) create mode 100644 tests/run/java-no-scala-import/Config.java create mode 100644 tests/run/java-no-scala-import/Test.scala diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index 53c4be27d8ce..96c9a647b960 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -7,7 +7,8 @@ import Periods._ import Symbols._ import Types._ import Scopes._ -import typer.{ImportInfo, Typer} +import typer.Typer +import typer.ImportInfo._ import Decorators._ import io.{AbstractFile, PlainFile} import Phases.unfusedPhases @@ -74,9 +75,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint .addMode(Mode.ImplicitsEnabled) .setTyperState(ctx.typerState.fresh(ctx.reporter)) ctx.initialize()(using start) // re-initialize the base context with start - def addImport(ctx: Context, rootRef: ImportInfo.RootRef) = - ctx.fresh.setImportInfo(ImportInfo.rootImport(rootRef)) - defn.RootImportFns.foldLeft(start.setRun(this))(addImport) + start.setRun(this) } private var compiling = false @@ -92,8 +91,8 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint private var myFiles: Set[AbstractFile] = _ /** The compilation units currently being compiled, this may return different - * results over time. - */ + * results over time. + */ def units: List[CompilationUnit] = myUnits var suspendedUnits: mutable.ListBuffer[CompilationUnit] = mutable.ListBuffer() @@ -205,7 +204,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint compiling = false } - /** Enter top-level definitions of classes and objects contain in Scala source file `file`. + /** Enter top-level definitions of classes and objects contained in source file `file`. * The newly added symbols replace any previously entered symbols. * If `typeCheck = true`, also run typer on the compilation unit, and set * `rootTreeOrProvider`. @@ -213,7 +212,12 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint def lateCompile(file: AbstractFile, typeCheck: Boolean)(using Context): Unit = if (!files.contains(file) && !lateFiles.contains(file)) { lateFiles += file + val unit = CompilationUnit(ctx.getSource(file.path)) + val unitCtx = runContext.fresh + .setCompilationUnit(unit) + .withRootImports + def process()(using Context) = { unit.untpdTree = if (unit.isJava) new JavaParser(unit.source).parse() @@ -227,7 +231,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint if (typeCheck) if (compiling) finalizeActions += (() => processUnit()) else processUnit() } - process()(using runContext.fresh.setCompilationUnit(unit)) + process()(using unitCtx) } private sealed trait PrintedTree diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 1f7b51bf78e7..8d88ba1138e6 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1140,28 +1140,61 @@ class Definitions { def isPredefClass(cls: Symbol): Boolean = (cls.owner eq ScalaPackageClass) && predefClassNames.contains(cls.name) - val StaticRootImportFns: List[RootRef] = List[RootRef]( - (() => JavaLangPackageVal.termRef, false), - (() => ScalaPackageVal.termRef, false) + private val JavaImportFns: List[RootRef] = List( + RootRef(() => JavaLangPackageVal.termRef) ) - val PredefImportFns: List[RootRef] = List[RootRef]( - (() => ScalaPredefModule.termRef, true), - (() => DottyPredefModule.termRef, false) + private val ScalaImportFns: List[RootRef] = + JavaImportFns :+ + RootRef(() => ScalaPackageVal.termRef) + + private val PredefImportFns: List[RootRef] = List( + RootRef(() => ScalaPredefModule.termRef, isPredef=true), + RootRef(() => DottyPredefModule.termRef) ) - @tu lazy val RootImportFns: List[RootRef] = - if (ctx.settings.YnoImports.value) Nil - else if (ctx.settings.YnoPredef.value) StaticRootImportFns - else StaticRootImportFns ++ PredefImportFns + @tu private lazy val JavaRootImportFns: List[RootRef] = + if ctx.settings.YnoImports.value then Nil + else JavaImportFns - @tu lazy val ShadowableImportNames: Set[TermName] = Set("Predef", "DottyPredef").map(_.toTermName) - @tu lazy val RootImportTypes: List[TermRef] = RootImportFns.map(_._1()) + @tu private lazy val ScalaRootImportFns: List[RootRef] = + if ctx.settings.YnoImports.value then Nil + else if ctx.settings.YnoPredef.value then ScalaImportFns + else ScalaImportFns ++ PredefImportFns + + @tu private lazy val JavaRootImportTypes: List[TermRef] = JavaRootImportFns.map(_.refFn()) + @tu private lazy val ScalaRootImportTypes: List[TermRef] = ScalaRootImportFns.map(_.refFn()) + @tu private lazy val JavaUnqualifiedOwnerTypes: Set[NamedType] = unqualifiedTypes(JavaRootImportTypes) + @tu private lazy val ScalaUnqualifiedOwnerTypes: Set[NamedType] = unqualifiedTypes(ScalaRootImportTypes) + + /** Are we compiling a java source file? */ + private def isJavaContext(using Context): Boolean = + val unit = ctx.compilationUnit + unit != null && unit.isJava + + private def unqualifiedTypes(refs: List[TermRef]) = + val types = refs.toSet[NamedType] + types ++ types.map(_.symbol.moduleClass.typeRef) + + /** Lazy references to the root imports */ + def rootImportFns(using Context): List[RootRef] = + if isJavaContext then JavaRootImportFns + else ScalaRootImportFns + + /** Root types imported by default */ + def rootImportTypes(using Context): List[TermRef] = + if isJavaContext then JavaRootImportTypes + else ScalaRootImportTypes /** Modules whose members are in the default namespace and their module classes */ - @tu lazy val UnqualifiedOwnerTypes: Set[NamedType] = - RootImportTypes.toSet[NamedType] ++ RootImportTypes.map(_.symbol.moduleClass.typeRef) + def unqualifiedOwnerTypes(using Context): Set[NamedType] = + if isJavaContext then JavaUnqualifiedOwnerTypes + else ScalaUnqualifiedOwnerTypes + + /** Names of the root import symbols that can be hidden by other imports */ + @tu lazy val ShadowableImportNames: Set[TermName] = Set("Predef", "DottyPredef").map(_.toTermName) + /** Class symbols for which no class exist at runtime */ @tu lazy val NotRuntimeClasses: Set[Symbol] = Set(AnyClass, AnyValClass, NullClass, NothingClass) /** Classes that are known not to have an initializer irrespective of diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala index 994cc3ff05a3..1106f3fcf199 100644 --- a/compiler/src/dotty/tools/dotc/core/Phases.scala +++ b/compiler/src/dotty/tools/dotc/core/Phases.scala @@ -14,6 +14,7 @@ import dotty.tools.dotc.transform.MegaPhase._ import dotty.tools.dotc.transform._ import Periods._ import typer.{FrontEnd, RefChecks} +import typer.ImportInfo.withRootImports import ast.tpd object Phases { @@ -291,7 +292,7 @@ object Phases { /** @pre `isRunnable` returns true */ def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] = units.map { unit => - val unitCtx = ctx.fresh.setPhase(this.start).setCompilationUnit(unit) + val unitCtx = ctx.fresh.setPhase(this.start).setCompilationUnit(unit).withRootImports run(using unitCtx) unitCtx.compilationUnit } diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index 467228ded06b..3c226cd5d792 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -101,7 +101,7 @@ object JavaParsers { def javaLangObject(): Tree = javaLangDot(tpnme.Object) def arrayOf(tpt: Tree): AppliedTypeTree = - AppliedTypeTree(Ident(nme.Array.toTypeName), List(tpt)) + AppliedTypeTree(scalaDot(tpnme.Array), List(tpt)) def makeTemplate(parents: List[Tree], stats: List[Tree], tparams: List[TypeDef], needsDummyConstr: Boolean): Template = { def pullOutFirstConstr(stats: List[Tree]): (Tree, List[Tree]) = stats match { diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 668ed1d9c3a6..8b41983bad27 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -321,7 +321,7 @@ class PlainPrinter(_ctx: Context) extends Printer { } protected def isOmittablePrefix(sym: Symbol): Boolean = - defn.UnqualifiedOwnerTypes.exists(_.symbol == sym) || isEmptyPrefix(sym) + defn.unqualifiedOwnerTypes.exists(_.symbol == sym) || isEmptyPrefix(sym) protected def isEmptyPrefix(sym: Symbol): Boolean = sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 0ac620b804c4..584909eb8776 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -664,7 +664,7 @@ class SpaceEngine(using Context) extends SpaceLogic { def isOmittable(sym: Symbol) = sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName || - ctx.definitions.UnqualifiedOwnerTypes.exists(_.symbol == sym) || + ctx.definitions.unqualifiedOwnerTypes.exists(_.symbol == sym) || sym.showFullName.startsWith("scala.") || sym == enclosingCls || sym == enclosingCls.sourceModule diff --git a/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala b/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala index 774cac41cecd..987af1c89774 100644 --- a/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala +++ b/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala @@ -7,7 +7,8 @@ import Phases._ import Contexts._ import Symbols._ import Decorators._ -import dotty.tools.dotc.parsing.JavaParsers.JavaParser +import ImportInfo.withRootImports +import parsing.JavaParsers.JavaParser import parsing.Parsers.Parser import config.Config import config.Printers.{typr, default} @@ -98,7 +99,7 @@ class FrontEnd extends Phase { val unitContexts = for unit <- units yield report.inform(s"compiling ${unit.source}") - ctx.fresh.setCompilationUnit(unit) + ctx.fresh.setCompilationUnit(unit).withRootImports unitContexts.foreach(parse(using _)) record("parsedTrees", ast.Trees.ntrees) remaining = unitContexts @@ -123,7 +124,7 @@ class FrontEnd extends Phase { | ${suspendedUnits.toList}%, % |""" val enableXprintSuspensionHint = - if (ctx.settings.XprintSuspension.value) "" + if ctx.settings.XprintSuspension.value then "" else "\n\nCompiling with -Xprint-suspension gives more information." report.error(em"""Cyclic macro dependencies $where |Compilation stopped since no further progress can be made. diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index 6ac9fa4535a2..6704ffd1157f 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -17,24 +17,32 @@ import Decorators._ object ImportInfo { - type RootRef = ( - () => TermRef, // a lazy reference to the root module to be imported - Boolean // true if this will refer to scala.Predef - ) - - /** The import info for a root import from given symbol `sym` */ - def rootImport(rootRef: RootRef)(using Context): ImportInfo = - val (refFn, isPredef) = rootRef + case class RootRef(refFn: () => TermRef, isPredef: Boolean = false) + + /** The import info for a root import */ + def rootImport(ref: RootRef)(using Context): ImportInfo = var selectors = untpd.ImportSelector(untpd.Ident(nme.WILDCARD)) // import all normal members... :: untpd.ImportSelector(untpd.Ident(nme.EMPTY)) // ... and also all given members :: Nil - if isPredef then // do not import any2stringadd + if ref.isPredef then // do not import any2stringadd selectors = untpd.ImportSelector(untpd.Ident(nme.any2stringadd), untpd.Ident(nme.WILDCARD)) :: selectors - def expr(using Context) = tpd.Ident(refFn()) - def imp(using Context) = tpd.Import(expr, selectors) - ImportInfo(imp.symbol, selectors, None, isRootImport = true) + + def sym(using Context) = + val expr = tpd.Ident(ref.refFn()) // refFn must be called in the context of ImportInfo.sym + tpd.Import(expr, selectors).symbol + + ImportInfo(sym, selectors, None, isRootImport = true) + + extension (c: Context): + def withRootImports(rootRefs: List[RootRef])(using Context): Context = + rootRefs.foldLeft(c)((ctx, ref) => ctx.fresh.setImportInfo(rootImport(ref))) + + def withRootImports: Context = + given Context = c + c.withRootImports(defn.rootImportFns) + } /** Info relating to an import clause @@ -164,7 +172,7 @@ class ImportInfo(symf: Context ?=> Symbol, case Some(symName) => defn.ShadowableImportNames.contains(symName) case None => false myUnimported = - if maybeShadowsRoot && defn.RootImportTypes.exists(_.symbol == sym) then sym + if maybeShadowsRoot && defn.rootImportTypes.exists(_.symbol == sym) then sym else NoSymbol assert(myUnimported != null) myUnimported @@ -193,4 +201,4 @@ class ImportInfo(symf: Context ?=> Symbol, end featureImported def toText(printer: Printer): Text = printer.toText(this) -} \ No newline at end of file +} diff --git a/compiler/src/dotty/tools/dotc/typer/ImportSuggestions.scala b/compiler/src/dotty/tools/dotc/typer/ImportSuggestions.scala index 16e8b9bc5c04..7fa03a78e25d 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportSuggestions.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportSuggestions.scala @@ -226,7 +226,7 @@ trait ImportSuggestions: try val roots = suggestionRoots - .filterNot(root => defn.RootImportTypes.exists(_.symbol == root.symbol)) + .filterNot(root => defn.rootImportTypes.exists(_.symbol == root.symbol)) // don't suggest things that are imported by default def extensionImports = pt match diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 7ad0a4cd236a..dc5e9b87b715 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -13,7 +13,7 @@ import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.reporting.Diagnostic import dotty.tools.dotc.transform.{PostTyper, Staging} -import dotty.tools.dotc.typer.ImportInfo +import dotty.tools.dotc.typer.ImportInfo._ import dotty.tools.dotc.util.Spans._ import dotty.tools.dotc.util.{ParsedComment, SourceFile} import dotty.tools.dotc.{CompilationUnit, Compiler, Run} @@ -48,21 +48,19 @@ class ReplCompiler extends Compiler { def importPreviousRun(id: Int)(using Context) = { // we first import the wrapper object id val path = nme.EMPTY_PACKAGE ++ "." ++ objectNames(id) - def importWrapper(c: Context, importGiven: Boolean) = { - val importInfo = ImportInfo.rootImport(() => - requiredModuleRef(path), importGiven)(using c) - c.fresh.setNewScope.setImportInfo(importInfo) - } - val ctx0 = importWrapper(importWrapper(ctx, false), true) + val ctx0 = ctx.fresh + .setNewScope + .withRootImports(RootRef(() => requiredModuleRef(path)) :: Nil) // then its user defined imports val imports = state.imports.getOrElse(id, Nil) - if (imports.isEmpty) ctx0 + if imports.isEmpty then ctx0 else imports.foldLeft(ctx0.fresh.setNewScope)((ctx, imp) => importContext(imp)(using ctx)) } - (1 to state.objectIndex).foldLeft(super.rootContext)((ctx, id) => + val rootCtx = super.rootContext.withRootImports + (1 to state.objectIndex).foldLeft(rootCtx)((ctx, id) => importPreviousRun(id)(using ctx)) } } diff --git a/compiler/src/dotty/tools/repl/ReplFrontEnd.scala b/compiler/src/dotty/tools/repl/ReplFrontEnd.scala index 8e07ccdfe0c3..59df49e853cb 100644 --- a/compiler/src/dotty/tools/repl/ReplFrontEnd.scala +++ b/compiler/src/dotty/tools/repl/ReplFrontEnd.scala @@ -4,6 +4,7 @@ package repl import dotc.typer.FrontEnd import dotc.CompilationUnit import dotc.core.Contexts._ +import dotc.typer.ImportInfo.withRootImports /** A customized `FrontEnd` for the REPL * @@ -17,10 +18,10 @@ private[repl] class REPLFrontEnd extends FrontEnd { override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] = { assert(units.size == 1) // REPl runs one compilation unit at a time - - val unitContext = ctx.fresh.setCompilationUnit(units.head) + val unit = units.head + val unitContext = ctx.fresh.setCompilationUnit(unit).withRootImports enterSyms(using unitContext) typeCheck(using unitContext) - List(unitContext.compilationUnit) + List(unit) } } diff --git a/tests/run/java-no-scala-import/Config.java b/tests/run/java-no-scala-import/Config.java new file mode 100644 index 000000000000..5fe636f424ee --- /dev/null +++ b/tests/run/java-no-scala-import/Config.java @@ -0,0 +1,25 @@ +public class Config { + long longVal; + Long longObj; + Integer boxed; + + public long getLongVal() { + return longVal; + } + + public void setLongVal(long longVal) { + this.longVal = longVal; + } + + public Long getLongObj() { + return longObj; + } + + public void setLongObj(Long longObj) { + this.longObj = longObj; + } + + public Long longLength(String str) { + return Long.valueOf(str.length()); + } +} diff --git a/tests/run/java-no-scala-import/Test.scala b/tests/run/java-no-scala-import/Test.scala new file mode 100644 index 000000000000..cdc46d2b3e0e --- /dev/null +++ b/tests/run/java-no-scala-import/Test.scala @@ -0,0 +1,6 @@ +object Test extends App { + val c = new Config() + c.setLongObj(10) + println(c.getLongObj) + val l = c.longLength("test") +}