Skip to content

Commit 40593a5

Browse files
committed
Fix :require adding classes/pkgs
1 parent 92232be commit 40593a5

File tree

9 files changed

+52
-42
lines changed

9 files changed

+52
-42
lines changed

Diff for: compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala

+1-5
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,7 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath {
3333
packageIndex.getOrElseUpdate(pkg.dottedString, aggregates.filter(_.hasPackage(pkg)))
3434
}
3535

36-
override def asURLs: Seq[URL] =
37-
aggregates.flatMap {
38-
case v: VirtualDirectoryClassPath => Seq()
39-
case a => a.asURLs
40-
}
36+
override def asURLs: Seq[URL] = aggregates.flatMap(_.asURLs)
4137

4238
override def asClassPathStrings: Seq[String] = aggregates.map(_.asClassPathString).distinct
4339

Diff for: compiler/src/dotty/tools/dotc/config/JavaPlatform.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ class JavaPlatform extends Platform {
3333
case cp: ClassPath =>
3434
currentClassPath = Some(AggregateClassPath(cp :: cPath :: Nil))
3535
}
36+
3637
/** Update classpath with a substituted subentry */
37-
def updateClassPath(subst: Map[ClassPath, ClassPath])(using Context): Unit = classPath match {
38+
def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit = currentClassPath.get match {
3839
case AggregateClassPath(entries) =>
3940
currentClassPath = Some(AggregateClassPath(entries map (e => subst.getOrElse(e, e))))
4041
case cp: ClassPath =>

Diff for: compiler/src/dotty/tools/dotc/config/Platform.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ abstract class Platform {
1919
def classPath(using Context): ClassPath
2020

2121
/** Update classpath with a substitution that maps entries to entries */
22-
def updateClassPath(subst: Map[ClassPath, ClassPath])(using Context): Unit
22+
def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit
2323

2424
/** Add new entry to classpath */
2525
def addToClassPath(cPath: ClassPath)(using Context): Unit

Diff for: compiler/src/dotty/tools/dotc/core/Contexts.scala

+1-5
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import scala.annotation.internal.sharable
3636
import DenotTransformers.DenotTransformer
3737
import dotty.tools.dotc.profile.Profiler
3838
import dotty.tools.dotc.sbt.interfaces.{IncrementalCallback, ProgressCallback}
39-
import dotty.tools.dotc.classpath.ClassPathFactory
4039
import util.Property.Key
4140
import util.Store
4241
import plugins.*
@@ -919,11 +918,8 @@ object Contexts {
919918
/** Initializes the `ContextBase` with a starting context.
920919
* This initializes the `platform` and the `definitions`.
921920
*/
922-
def initialize(previousOutputDir: Option[AbstractFile] = None)(using Context): Unit = {
921+
def initialize()(using Context): Unit = {
923922
_platform = newPlatform
924-
previousOutputDir.foreach(cp =>
925-
_platform.nn.addToClassPath(ClassPathFactory.newClassPath(cp))
926-
)
927923
definitions.init()
928924
}
929925

Diff for: compiler/src/dotty/tools/dotc/core/Definitions.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -2220,7 +2220,7 @@ class Definitions {
22202220

22212221
private var isInitialized = false
22222222

2223-
def init(require: Boolean = false)(using Context): Unit = {
2223+
def init()(using Context): Unit = {
22242224
this.initCtx = ctx
22252225
if (!isInitialized) {
22262226
// force initialization of every symbol that is synthesized or hijacked by the compiler

Diff for: compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala

+28-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import java.nio.channels.ClosedByInterruptException
77

88
import scala.util.control.NonFatal
99

10+
import dotty.tools.dotc.classpath.{ ClassPathFactory, PackageNameUtils }
1011
import dotty.tools.dotc.classpath.FileUtils.{hasTastyExtension, hasBetastyExtension}
1112
import dotty.tools.io.{ ClassPath, ClassRepresentation, AbstractFile, NoAbstractFile }
1213
import dotty.tools.backend.jvm.DottyBackendInterface.symExtensions
@@ -272,7 +273,7 @@ object SymbolLoaders {
272273
def maybeModuleClass(classRep: ClassRepresentation): Boolean =
273274
classRep.name.nonEmpty && classRep.name.last == '$'
274275

275-
private def enterClasses(root: SymDenotation, packageName: String, flat: Boolean)(using Context) = {
276+
def enterClasses(root: SymDenotation, packageName: String, flat: Boolean)(using Context) = {
276277
def isAbsent(classRep: ClassRepresentation) =
277278
!root.unforcedDecls.lookup(classRep.name.toTypeName).exists
278279

@@ -316,6 +317,32 @@ object SymbolLoaders {
316317
}
317318
}
318319
}
320+
321+
def mergeNewEntries(
322+
packageClass: ClassSymbol, fullPackageName: String,
323+
jarClasspath: ClassPath, fullClasspath: ClassPath,
324+
)(using Context): Unit =
325+
if jarClasspath.classes(fullPackageName).nonEmpty then
326+
// if the package contains classes in jarClasspath, the package is invalidated (or removed if there are no more classes in it)
327+
val packageVal = packageClass.sourceModule.asInstanceOf[TermSymbol]
328+
if packageClass.isRoot then
329+
val loader = new PackageLoader(packageVal, fullClasspath)
330+
loader.enterClasses(defn.EmptyPackageClass, fullPackageName, flat = false)
331+
loader.enterClasses(defn.EmptyPackageClass, fullPackageName, flat = true)
332+
else if packageClass.ownersIterator.contains(defn.ScalaPackageClass) then
333+
() // skip
334+
else if fullClasspath.hasPackage(fullPackageName) then
335+
packageClass.info = new PackageLoader(packageVal, fullClasspath)
336+
else
337+
packageClass.owner.info.decls.openForMutations.unlink(packageVal)
338+
else
339+
for p <- jarClasspath.packages(fullPackageName) do
340+
val subPackageName = PackageNameUtils.separatePkgAndClassNames(p.name)._2.toTermName
341+
val subPackage = packageClass.info.decl(subPackageName).orElse:
342+
// package does not exist in symbol table, create a new symbol
343+
enterPackage(packageClass, subPackageName, (module, modcls) => new PackageLoader(module, fullClasspath))
344+
mergeNewEntries(subPackage.asSymDenotation.moduleClass.asClass, p.name, jarClasspath, fullClasspath)
345+
end mergeNewEntries
319346
}
320347

321348
/** A lazy type that completes itself by calling parameter doComplete.

Diff for: compiler/src/dotty/tools/repl/ReplCompiler.scala

+1-5
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,7 @@ class ReplCompiler extends Compiler:
4646
/** Import previous runs and user defined imports */
4747
override protected def rootContext(using Context): Context = {
4848
def importContext(imp: tpd.Import)(using Context) =
49-
// TODO: only when context has changed?
50-
val typer = ctx.typer
51-
typer.index(imp)
52-
val imp2 = typer.typed(imp).asInstanceOf[tpd.Import]
53-
ctx.importContext(imp2, imp2.symbol)
49+
ctx.importContext(imp, imp.symbol)
5450

5551
def importPreviousRun(id: Int)(using Context) = {
5652
// we first import the wrapper object id

Diff for: compiler/src/dotty/tools/repl/ReplDriver.scala

+16-19
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package dotty.tools.repl
22

33
import scala.language.unsafeNulls
4+
45
import java.io.{File => JFile, PrintStream}
56
import java.nio.charset.StandardCharsets
7+
68
import dotty.tools.dotc.ast.Trees.*
79
import dotty.tools.dotc.ast.{tpd, untpd}
810
import dotty.tools.dotc.classpath.ClassPathFactory
@@ -20,6 +22,7 @@ import dotty.tools.dotc.core.NameOps.*
2022
import dotty.tools.dotc.core.Names.Name
2123
import dotty.tools.dotc.core.StdNames.*
2224
import dotty.tools.dotc.core.Symbols.{Symbol, defn}
25+
import dotty.tools.dotc.core.SymbolLoaders
2326
import dotty.tools.dotc.interfaces
2427
import dotty.tools.dotc.interactive.Completion
2528
import dotty.tools.dotc.printing.SyntaxHighlighting
@@ -70,6 +73,7 @@ case class State(objectIndex: Int,
7073
quiet: Boolean,
7174
context: Context):
7275
def validObjectIndexes = (1 to objectIndex).filterNot(invalidObjectIndexes.contains(_))
76+
//def copy() = this
7377

7478
/** Main REPL instance, orchestrating input, compilation and presentation */
7579
class ReplDriver(settings: Array[String],
@@ -94,7 +98,7 @@ class ReplDriver(settings: Array[String],
9498
initCtx.settings.YwithBestEffortTasty.name
9599
)
96100

97-
private def setupRootCtx(settings: Array[String], rootCtx: Context, previousOutputDir: Option[AbstractFile] = None) = {
101+
private def setupRootCtx(settings: Array[String], rootCtx: Context) = {
98102
val incompatible = settings.intersect(incompatibleOptions)
99103
val filteredSettings =
100104
if !incompatible.isEmpty then
@@ -107,7 +111,7 @@ class ReplDriver(settings: Array[String],
107111
case Some((files, ictx)) => inContext(ictx) {
108112
shouldStart = true
109113
if files.nonEmpty then out.println(i"Ignoring spurious arguments: $files%, %")
110-
ictx.base.initialize(previousOutputDir)
114+
ictx.base.initialize()
111115
ictx
112116
}
113117
case None =>
@@ -540,30 +544,23 @@ class ReplDriver(settings: Array[String],
540544
if (existingClass.nonEmpty)
541545
out.println(s"The path '$path' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}")
542546
state
543-
else
544-
val prevClassPath = state.context.platform.classPath(using state.context).asClassPathString
545-
val newClassPath = s"$prevClassPath${JFile.pathSeparator}$path"
547+
else inContext(state.context):
548+
val jarClassPath = ClassPathFactory.newClassPath(jarFile)
549+
val prevOutputDir = ctx.settings.outputDir.value
546550

547551
// add to compiler class path
548-
val prevOutputDir = rootCtx.settings.outputDir.valueIn(rootCtx.settingsState)
549-
val ctxToUse = initCtx.fresh
550-
.setSetting(rootCtx.settings.classpath, newClassPath)
551-
.setSetting(rootCtx.settings.outputDir, prevOutputDir) // reuse virtual output directory
552-
rootCtx = setupRootCtx(
553-
Array(),
554-
ctxToUse,
555-
previousOutputDir = Some(prevOutputDir)
556-
)
557-
val s = state.copy(context = rootCtx)
552+
ctx.platform.addToClassPath(jarClassPath)
553+
SymbolLoaders.mergeNewEntries(defn.RootClass, ClassPath.RootPackage, jarClassPath, ctx.platform.classPath)
558554

559555
// new class loader with previous output dir and specified jar
560-
val prevClassLoader = rendering.classLoader()(using state.context)
556+
val prevClassLoader = rendering.classLoader()
561557
val jarClassLoader = fromURLsParallelCapable(
562-
ClassPathFactory.newClassPath(jarFile)(using rootCtx).asURLs, prevClassLoader)
558+
jarClassPath.asURLs, prevClassLoader)
563559
rendering.myClassLoader = new AbstractFileClassLoader(
564-
rootCtx.settings.outputDir.valueIn(rootCtx.settingsState), jarClassLoader)
560+
prevOutputDir, jarClassLoader)
561+
565562
out.println(s"Added '$path' to classpath.")
566-
s
563+
state
567564

568565
case TypeOf(expr) =>
569566
expr match {

Diff for: compiler/test/dotty/tools/repl/ReplTest.scala

+1-4
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,7 @@ extends ReplDriver(options, new PrintStream(out, true, StandardCharsets.UTF_8.na
9898
FileDiff.dump(checkFile.toPath.toString, actualOutput)
9999
println(s"Wrote updated script file to $checkFile")
100100
else
101-
println("expected =========>")
102-
println(expectedOutput.mkString(EOL))
103-
println("actual ===========>")
104-
println(actualOutput.mkString(EOL))
101+
println(dotc.util.DiffUtil.mkColoredHorizontalLineDiff(actualOutput.mkString(EOL), expectedOutput.mkString(EOL)))
105102

106103
fail(s"Error in script $name, expected output did not match actual")
107104
end if

0 commit comments

Comments
 (0)