Skip to content

Commit c5e7432

Browse files
dwijnandtgodzik
authored andcommitted
Fix :require adding classes/pkgs
1 parent 6aa591d commit c5e7432

File tree

9 files changed

+52
-42
lines changed

9 files changed

+52
-42
lines changed

compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,7 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath {
5252
}
5353
}
5454

55-
override def asURLs: Seq[URL] =
56-
aggregates.flatMap {
57-
case v: VirtualDirectoryClassPath => Seq()
58-
case a => a.asURLs
59-
}
55+
override def asURLs: Seq[URL] = aggregates.flatMap(_.asURLs)
6056

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

compiler/src/dotty/tools/dotc/config/JavaPlatform.scala

Lines changed: 2 additions & 1 deletion
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 =>

compiler/src/dotty/tools/dotc/config/Platform.scala

Lines changed: 1 addition & 1 deletion
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

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import scala.annotation.internal.sharable
3535
import DenotTransformers.DenotTransformer
3636
import dotty.tools.dotc.profile.Profiler
3737
import dotty.tools.dotc.sbt.interfaces.{IncrementalCallback, ProgressCallback}
38-
import dotty.tools.dotc.classpath.ClassPathFactory
3938
import util.Property.Key
4039
import util.Store
4140
import plugins.*
@@ -898,11 +897,8 @@ object Contexts {
898897
/** Initializes the `ContextBase` with a starting context.
899898
* This initializes the `platform` and the `definitions`.
900899
*/
901-
def initialize(previousOutputDir: Option[AbstractFile] = None)(using Context): Unit = {
900+
def initialize()(using Context): Unit = {
902901
_platform = newPlatform
903-
previousOutputDir.foreach(cp =>
904-
_platform.nn.addToClassPath(ClassPathFactory.newClassPath(cp))
905-
)
906902
definitions.init()
907903
}
908904

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2150,7 +2150,7 @@ class Definitions {
21502150

21512151
private var isInitialized = false
21522152

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

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

Lines changed: 28 additions & 1 deletion
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.PackageNameUtils
1011
import dotty.tools.io.{ ClassPath, ClassRepresentation, AbstractFile, NoAbstractFile }
1112
import dotty.tools.backend.jvm.DottyBackendInterface.symExtensions
1213

@@ -265,7 +266,7 @@ object SymbolLoaders {
265266

266267
def maybeModuleClass(classRep: ClassRepresentation): Boolean = classRep.name.last == '$'
267268

268-
private def enterClasses(root: SymDenotation, packageName: String, flat: Boolean)(using Context) = {
269+
def enterClasses(root: SymDenotation, packageName: String, flat: Boolean)(using Context) = {
269270
def isAbsent(classRep: ClassRepresentation) =
270271
!root.unforcedDecls.lookup(classRep.name.toTypeName).exists
271272

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

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

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

Lines changed: 1 addition & 5 deletions
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

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

Lines changed: 16 additions & 19 deletions
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
@@ -69,6 +72,7 @@ case class State(objectIndex: Int,
6972
quiet: Boolean,
7073
context: Context):
7174
def validObjectIndexes = (1 to objectIndex).filterNot(invalidObjectIndexes.contains(_))
75+
//def copy() = this
7276

7377
/** Main REPL instance, orchestrating input, compilation and presentation */
7478
class ReplDriver(settings: Array[String],
@@ -88,12 +92,12 @@ class ReplDriver(settings: Array[String],
8892
setupRootCtx(this.settings ++ settings, rootCtx)
8993
}
9094

91-
private def setupRootCtx(settings: Array[String], rootCtx: Context, previousOutputDir: Option[AbstractFile] = None) = {
95+
private def setupRootCtx(settings: Array[String], rootCtx: Context) = {
9296
setup(settings, rootCtx) match
9397
case Some((files, ictx)) => inContext(ictx) {
9498
shouldStart = true
9599
if files.nonEmpty then out.println(i"Ignoring spurious arguments: $files%, %")
96-
ictx.base.initialize(previousOutputDir)
100+
ictx.base.initialize()
97101
ictx
98102
}
99103
case None =>
@@ -543,30 +547,23 @@ class ReplDriver(settings: Array[String],
543547
if (existingClass.nonEmpty)
544548
out.println(s"The path '$path' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}")
545549
state
546-
else
547-
val prevClassPath = state.context.platform.classPath(using state.context).asClassPathString
548-
val newClassPath = s"$prevClassPath${JFile.pathSeparator}$path"
550+
else inContext(state.context):
551+
val jarClassPath = ClassPathFactory.newClassPath(jarFile)
552+
val prevOutputDir = ctx.settings.outputDir.value
549553

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

562558
// new class loader with previous output dir and specified jar
563-
val prevClassLoader = rendering.classLoader()(using state.context)
559+
val prevClassLoader = rendering.classLoader()
564560
val jarClassLoader = fromURLsParallelCapable(
565-
ClassPathFactory.newClassPath(jarFile)(using rootCtx).asURLs, prevClassLoader)
561+
jarClassPath.asURLs, prevClassLoader)
566562
rendering.myClassLoader = new AbstractFileClassLoader(
567-
rootCtx.settings.outputDir.valueIn(rootCtx.settingsState), jarClassLoader)
563+
prevOutputDir, jarClassLoader)
564+
568565
out.println(s"Added '$path' to classpath.")
569-
s
566+
state
570567

571568
case KindOf(expr) =>
572569
out.println(s"""The :kind command is not currently supported.""")

compiler/test/dotty/tools/repl/ReplTest.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,7 @@ extends ReplDriver(options, new PrintStream(out, true, StandardCharsets.UTF_8.na
9494
FileDiff.dump(checkFile.toPath.toString, actualOutput)
9595
println(s"Wrote updated script file to $checkFile")
9696
else
97-
println("expected =========>")
98-
println(expectedOutput.mkString(EOL))
99-
println("actual ===========>")
100-
println(actualOutput.mkString(EOL))
97+
println(dotc.util.DiffUtil.mkColoredHorizontalLineDiff(actualOutput.mkString(EOL), expectedOutput.mkString(EOL)))
10198

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

0 commit comments

Comments
 (0)