Skip to content

Commit 7735c04

Browse files
authored
Merge pull request #9394 from TheElectronWill/fix/7312
Fix #7312: Choose root imports based on the source file
2 parents 5856123 + 6990aab commit 7735c04

File tree

13 files changed

+132
-55
lines changed

13 files changed

+132
-55
lines changed

compiler/src/dotty/tools/dotc/Run.scala

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import Periods._
77
import Symbols._
88
import Types._
99
import Scopes._
10-
import typer.{ImportInfo, Typer}
10+
import typer.Typer
11+
import typer.ImportInfo._
1112
import Decorators._
1213
import io.{AbstractFile, PlainFile}
1314
import Phases.unfusedPhases
@@ -74,9 +75,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
7475
.addMode(Mode.ImplicitsEnabled)
7576
.setTyperState(ctx.typerState.fresh(ctx.reporter))
7677
ctx.initialize()(using start) // re-initialize the base context with start
77-
def addImport(ctx: Context, rootRef: ImportInfo.RootRef) =
78-
ctx.fresh.setImportInfo(ImportInfo.rootImport(rootRef))
79-
defn.RootImportFns.foldLeft(start.setRun(this))(addImport)
78+
start.setRun(this)
8079
}
8180

8281
private var compiling = false
@@ -92,8 +91,8 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
9291
private var myFiles: Set[AbstractFile] = _
9392

9493
/** The compilation units currently being compiled, this may return different
95-
* results over time.
96-
*/
94+
* results over time.
95+
*/
9796
def units: List[CompilationUnit] = myUnits
9897

9998
var suspendedUnits: mutable.ListBuffer[CompilationUnit] = mutable.ListBuffer()
@@ -205,15 +204,20 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
205204
compiling = false
206205
}
207206

208-
/** Enter top-level definitions of classes and objects contain in Scala source file `file`.
207+
/** Enter top-level definitions of classes and objects contained in source file `file`.
209208
* The newly added symbols replace any previously entered symbols.
210209
* If `typeCheck = true`, also run typer on the compilation unit, and set
211210
* `rootTreeOrProvider`.
212211
*/
213212
def lateCompile(file: AbstractFile, typeCheck: Boolean)(using Context): Unit =
214213
if (!files.contains(file) && !lateFiles.contains(file)) {
215214
lateFiles += file
215+
216216
val unit = CompilationUnit(ctx.getSource(file.path))
217+
val unitCtx = runContext.fresh
218+
.setCompilationUnit(unit)
219+
.withRootImports
220+
217221
def process()(using Context) = {
218222
unit.untpdTree =
219223
if (unit.isJava) new JavaParser(unit.source).parse()
@@ -227,7 +231,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
227231
if (typeCheck)
228232
if (compiling) finalizeActions += (() => processUnit()) else processUnit()
229233
}
230-
process()(using runContext.fresh.setCompilationUnit(unit))
234+
process()(using unitCtx)
231235
}
232236

233237
private sealed trait PrintedTree

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,28 +1155,61 @@ class Definitions {
11551155
def isPredefClass(cls: Symbol): Boolean =
11561156
(cls.owner eq ScalaPackageClass) && predefClassNames.contains(cls.name)
11571157

1158-
val StaticRootImportFns: List[RootRef] = List[RootRef](
1159-
(() => JavaLangPackageVal.termRef, false),
1160-
(() => ScalaPackageVal.termRef, false)
1158+
private val JavaImportFns: List[RootRef] = List(
1159+
RootRef(() => JavaLangPackageVal.termRef)
11611160
)
11621161

1163-
val PredefImportFns: List[RootRef] = List[RootRef](
1164-
(() => ScalaPredefModule.termRef, true),
1165-
(() => DottyPredefModule.termRef, false)
1162+
private val ScalaImportFns: List[RootRef] =
1163+
JavaImportFns :+
1164+
RootRef(() => ScalaPackageVal.termRef)
1165+
1166+
private val PredefImportFns: List[RootRef] = List(
1167+
RootRef(() => ScalaPredefModule.termRef, isPredef=true),
1168+
RootRef(() => DottyPredefModule.termRef)
11661169
)
11671170

1168-
@tu lazy val RootImportFns: List[RootRef] =
1169-
if (ctx.settings.YnoImports.value) Nil
1170-
else if (ctx.settings.YnoPredef.value) StaticRootImportFns
1171-
else StaticRootImportFns ++ PredefImportFns
1171+
@tu private lazy val JavaRootImportFns: List[RootRef] =
1172+
if ctx.settings.YnoImports.value then Nil
1173+
else JavaImportFns
11721174

1173-
@tu lazy val ShadowableImportNames: Set[TermName] = Set("Predef", "DottyPredef").map(_.toTermName)
1174-
@tu lazy val RootImportTypes: List[TermRef] = RootImportFns.map(_._1())
1175+
@tu private lazy val ScalaRootImportFns: List[RootRef] =
1176+
if ctx.settings.YnoImports.value then Nil
1177+
else if ctx.settings.YnoPredef.value then ScalaImportFns
1178+
else ScalaImportFns ++ PredefImportFns
1179+
1180+
@tu private lazy val JavaRootImportTypes: List[TermRef] = JavaRootImportFns.map(_.refFn())
1181+
@tu private lazy val ScalaRootImportTypes: List[TermRef] = ScalaRootImportFns.map(_.refFn())
1182+
@tu private lazy val JavaUnqualifiedOwnerTypes: Set[NamedType] = unqualifiedTypes(JavaRootImportTypes)
1183+
@tu private lazy val ScalaUnqualifiedOwnerTypes: Set[NamedType] = unqualifiedTypes(ScalaRootImportTypes)
1184+
1185+
/** Are we compiling a java source file? */
1186+
private def isJavaContext(using Context): Boolean =
1187+
val unit = ctx.compilationUnit
1188+
unit != null && unit.isJava
1189+
1190+
private def unqualifiedTypes(refs: List[TermRef]) =
1191+
val types = refs.toSet[NamedType]
1192+
types ++ types.map(_.symbol.moduleClass.typeRef)
1193+
1194+
/** Lazy references to the root imports */
1195+
def rootImportFns(using Context): List[RootRef] =
1196+
if isJavaContext then JavaRootImportFns
1197+
else ScalaRootImportFns
1198+
1199+
/** Root types imported by default */
1200+
def rootImportTypes(using Context): List[TermRef] =
1201+
if isJavaContext then JavaRootImportTypes
1202+
else ScalaRootImportTypes
11751203

11761204
/** Modules whose members are in the default namespace and their module classes */
1177-
@tu lazy val UnqualifiedOwnerTypes: Set[NamedType] =
1178-
RootImportTypes.toSet[NamedType] ++ RootImportTypes.map(_.symbol.moduleClass.typeRef)
1205+
def unqualifiedOwnerTypes(using Context): Set[NamedType] =
1206+
if isJavaContext then JavaUnqualifiedOwnerTypes
1207+
else ScalaUnqualifiedOwnerTypes
1208+
1209+
/** Names of the root import symbols that can be hidden by other imports */
1210+
@tu lazy val ShadowableImportNames: Set[TermName] = Set("Predef", "DottyPredef").map(_.toTermName)
11791211

1212+
/** Class symbols for which no class exist at runtime */
11801213
@tu lazy val NotRuntimeClasses: Set[Symbol] = Set(AnyClass, AnyValClass, NullClass, NothingClass)
11811214

11821215
@tu lazy val SpecialClassTagClasses: Set[Symbol] = Set(UnitClass, AnyClass, AnyValClass)

compiler/src/dotty/tools/dotc/core/Phases.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import dotty.tools.dotc.transform.MegaPhase._
1414
import dotty.tools.dotc.transform._
1515
import Periods._
1616
import typer.{FrontEnd, RefChecks}
17+
import typer.ImportInfo.withRootImports
1718
import ast.tpd
1819

1920
object Phases {
@@ -291,7 +292,7 @@ object Phases {
291292
/** @pre `isRunnable` returns true */
292293
def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] =
293294
units.map { unit =>
294-
val unitCtx = ctx.fresh.setPhase(this.start).setCompilationUnit(unit)
295+
val unitCtx = ctx.fresh.setPhase(this.start).setCompilationUnit(unit).withRootImports
295296
run(using unitCtx)
296297
unitCtx.compilationUnit
297298
}

compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ object JavaParsers {
101101
def javaLangObject(): Tree = javaLangDot(tpnme.Object)
102102

103103
def arrayOf(tpt: Tree): AppliedTypeTree =
104-
AppliedTypeTree(Ident(nme.Array.toTypeName), List(tpt))
104+
AppliedTypeTree(scalaDot(tpnme.Array), List(tpt))
105105

106106
def makeTemplate(parents: List[Tree], stats: List[Tree], tparams: List[TypeDef], needsDummyConstr: Boolean): Template = {
107107
def pullOutFirstConstr(stats: List[Tree]): (Tree, List[Tree]) = stats match {

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
321321
}
322322

323323
protected def isOmittablePrefix(sym: Symbol): Boolean =
324-
defn.UnqualifiedOwnerTypes.exists(_.symbol == sym) || isEmptyPrefix(sym)
324+
defn.unqualifiedOwnerTypes.exists(_.symbol == sym) || isEmptyPrefix(sym)
325325

326326
protected def isEmptyPrefix(sym: Symbol): Boolean =
327327
sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
664664

665665
def isOmittable(sym: Symbol) =
666666
sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName ||
667-
ctx.definitions.UnqualifiedOwnerTypes.exists(_.symbol == sym) ||
667+
ctx.definitions.unqualifiedOwnerTypes.exists(_.symbol == sym) ||
668668
sym.showFullName.startsWith("scala.") ||
669669
sym == enclosingCls || sym == enclosingCls.sourceModule
670670

compiler/src/dotty/tools/dotc/typer/FrontEnd.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import Phases._
77
import Contexts._
88
import Symbols._
99
import Decorators._
10-
import dotty.tools.dotc.parsing.JavaParsers.JavaParser
10+
import ImportInfo.withRootImports
11+
import parsing.JavaParsers.JavaParser
1112
import parsing.Parsers.Parser
1213
import config.Config
1314
import config.Printers.{typr, default}
@@ -103,7 +104,7 @@ class FrontEnd extends Phase {
103104
val unitContexts =
104105
for unit <- units yield
105106
report.inform(s"compiling ${unit.source}")
106-
ctx.fresh.setCompilationUnit(unit)
107+
ctx.fresh.setCompilationUnit(unit).withRootImports
107108
unitContexts.foreach(parse(using _))
108109
record("parsedTrees", ast.Trees.ntrees)
109110
remaining = unitContexts

compiler/src/dotty/tools/dotc/typer/ImportInfo.scala

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,32 @@ import Decorators._
1717

1818
object ImportInfo {
1919

20-
type RootRef = (
21-
() => TermRef, // a lazy reference to the root module to be imported
22-
Boolean // true if this will refer to scala.Predef
23-
)
24-
25-
/** The import info for a root import from given symbol `sym` */
26-
def rootImport(rootRef: RootRef)(using Context): ImportInfo =
27-
val (refFn, isPredef) = rootRef
20+
case class RootRef(refFn: () => TermRef, isPredef: Boolean = false)
21+
22+
/** The import info for a root import */
23+
def rootImport(ref: RootRef)(using Context): ImportInfo =
2824
var selectors =
2925
untpd.ImportSelector(untpd.Ident(nme.WILDCARD)) // import all normal members...
3026
:: untpd.ImportSelector(untpd.Ident(nme.EMPTY)) // ... and also all given members
3127
:: Nil
32-
if isPredef then // do not import any2stringadd
28+
if ref.isPredef then // do not import any2stringadd
3329
selectors = untpd.ImportSelector(untpd.Ident(nme.any2stringadd), untpd.Ident(nme.WILDCARD))
3430
:: selectors
35-
def expr(using Context) = tpd.Ident(refFn())
36-
def imp(using Context) = tpd.Import(expr, selectors)
37-
ImportInfo(imp.symbol, selectors, None, isRootImport = true)
31+
32+
def sym(using Context) =
33+
val expr = tpd.Ident(ref.refFn()) // refFn must be called in the context of ImportInfo.sym
34+
tpd.Import(expr, selectors).symbol
35+
36+
ImportInfo(sym, selectors, None, isRootImport = true)
37+
38+
extension (c: Context):
39+
def withRootImports(rootRefs: List[RootRef])(using Context): Context =
40+
rootRefs.foldLeft(c)((ctx, ref) => ctx.fresh.setImportInfo(rootImport(ref)))
41+
42+
def withRootImports: Context =
43+
given Context = c
44+
c.withRootImports(defn.rootImportFns)
45+
3846
}
3947

4048
/** Info relating to an import clause
@@ -164,7 +172,7 @@ class ImportInfo(symf: Context ?=> Symbol,
164172
case Some(symName) => defn.ShadowableImportNames.contains(symName)
165173
case None => false
166174
myUnimported =
167-
if maybeShadowsRoot && defn.RootImportTypes.exists(_.symbol == sym) then sym
175+
if maybeShadowsRoot && defn.rootImportTypes.exists(_.symbol == sym) then sym
168176
else NoSymbol
169177
assert(myUnimported != null)
170178
myUnimported
@@ -193,4 +201,4 @@ class ImportInfo(symf: Context ?=> Symbol,
193201
end featureImported
194202

195203
def toText(printer: Printer): Text = printer.toText(this)
196-
}
204+
}

compiler/src/dotty/tools/dotc/typer/ImportSuggestions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ trait ImportSuggestions:
226226

227227
try
228228
val roots = suggestionRoots
229-
.filterNot(root => defn.RootImportTypes.exists(_.symbol == root.symbol))
229+
.filterNot(root => defn.rootImportTypes.exists(_.symbol == root.symbol))
230230
// don't suggest things that are imported by default
231231

232232
def extensionImports = pt match

compiler/src/dotty/tools/repl/ReplCompiler.scala

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import dotty.tools.dotc.core.StdNames._
1313
import dotty.tools.dotc.core.Symbols._
1414
import dotty.tools.dotc.reporting.Diagnostic
1515
import dotty.tools.dotc.transform.{PostTyper, Staging}
16-
import dotty.tools.dotc.typer.ImportInfo
16+
import dotty.tools.dotc.typer.ImportInfo._
1717
import dotty.tools.dotc.util.Spans._
1818
import dotty.tools.dotc.util.{ParsedComment, SourceFile}
1919
import dotty.tools.dotc.{CompilationUnit, Compiler, Run}
@@ -48,21 +48,19 @@ class ReplCompiler extends Compiler {
4848
def importPreviousRun(id: Int)(using Context) = {
4949
// we first import the wrapper object id
5050
val path = nme.EMPTY_PACKAGE ++ "." ++ objectNames(id)
51-
def importWrapper(c: Context, importGiven: Boolean) = {
52-
val importInfo = ImportInfo.rootImport(() =>
53-
requiredModuleRef(path), importGiven)(using c)
54-
c.fresh.setNewScope.setImportInfo(importInfo)
55-
}
56-
val ctx0 = importWrapper(importWrapper(ctx, false), true)
51+
val ctx0 = ctx.fresh
52+
.setNewScope
53+
.withRootImports(RootRef(() => requiredModuleRef(path)) :: Nil)
5754

5855
// then its user defined imports
5956
val imports = state.imports.getOrElse(id, Nil)
60-
if (imports.isEmpty) ctx0
57+
if imports.isEmpty then ctx0
6158
else imports.foldLeft(ctx0.fresh.setNewScope)((ctx, imp) =>
6259
importContext(imp)(using ctx))
6360
}
6461

65-
(1 to state.objectIndex).foldLeft(super.rootContext)((ctx, id) =>
62+
val rootCtx = super.rootContext.withRootImports
63+
(1 to state.objectIndex).foldLeft(rootCtx)((ctx, id) =>
6664
importPreviousRun(id)(using ctx))
6765
}
6866
}

compiler/src/dotty/tools/repl/ReplFrontEnd.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package repl
44
import dotc.typer.FrontEnd
55
import dotc.CompilationUnit
66
import dotc.core.Contexts._
7+
import dotc.typer.ImportInfo.withRootImports
78

89
/** A customized `FrontEnd` for the REPL
910
*
@@ -17,10 +18,10 @@ private[repl] class REPLFrontEnd extends FrontEnd {
1718

1819
override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] = {
1920
assert(units.size == 1) // REPl runs one compilation unit at a time
20-
21-
val unitContext = ctx.fresh.setCompilationUnit(units.head)
21+
val unit = units.head
22+
val unitContext = ctx.fresh.setCompilationUnit(unit).withRootImports
2223
enterSyms(using unitContext)
2324
typeCheck(using unitContext)
24-
List(unitContext.compilationUnit)
25+
List(unit)
2526
}
2627
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
public class Config {
2+
long longVal;
3+
Long longObj;
4+
Integer boxed;
5+
6+
public long getLongVal() {
7+
return longVal;
8+
}
9+
10+
public void setLongVal(long longVal) {
11+
this.longVal = longVal;
12+
}
13+
14+
public Long getLongObj() {
15+
return longObj;
16+
}
17+
18+
public void setLongObj(Long longObj) {
19+
this.longObj = longObj;
20+
}
21+
22+
public Long longLength(String str) {
23+
return Long.valueOf(str.length());
24+
}
25+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
object Test extends App {
2+
val c = new Config()
3+
c.setLongObj(10)
4+
println(c.getLongObj)
5+
val l = c.longLength("test")
6+
}

0 commit comments

Comments
 (0)