Skip to content

Commit 3d64fd5

Browse files
authored
Merge pull request #6595 from dotty-staging/remove-xml
Fix #5597: Remove scala-xml dependency, add it to the community-build
2 parents 2c26c17 + 1cf4190 commit 3d64fd5

File tree

17 files changed

+127
-79
lines changed

17 files changed

+127
-79
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@
3737
[submodule "community-build/community-projects/sourcecode"]
3838
path = community-build/community-projects/sourcecode
3939
url = https://github.com/dotty-staging/sourcecode
40+
[submodule "community-build/community-projects/scala-xml"]
41+
path = community-build/community-projects/scala-xml
42+
url = https://github.com/scala/scala-xml
Submodule scala-xml added at 19f53ad

community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ class CommunityBuildTest {
109109
updateCommand = "scalatest/update"
110110
)
111111

112+
@Test def scalaXml = test(
113+
project = "scala-xml",
114+
testCommand = "xml/test",
115+
updateCommand = "xml/update"
116+
)
117+
112118
@Test def scopt = test(
113119
project = "scopt",
114120
testCommand = "scoptJVM/compile",

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ class Definitions {
223223
lazy val Sys_errorR: TermRef = SysPackage.moduleClass.requiredMethodRef(nme.error)
224224
def Sys_error(implicit ctx: Context): Symbol = Sys_errorR.symbol
225225

226+
lazy val ScalaXmlPackageClass: Symbol = ctx.getPackageClassIfDefined("scala.xml")
227+
226228
lazy val CompiletimePackageObjectRef: TermRef = ctx.requiredModuleRef("scala.compiletime.package")
227229
lazy val CompiletimePackageObject: Symbol = CompiletimePackageObjectRef.symbol.moduleClass
228230
lazy val Compiletime_errorR: TermRef = CompiletimePackageObjectRef.symbol.requiredMethodRef(nme.error)

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,15 @@ trait Symbols { this: Context =>
383383
.requiredSymbol("class", name, generateStubs = false)(_.isClass)
384384
}
385385

386+
/** Get ClassSymbol if package is either defined in current compilation run
387+
* or present on classpath.
388+
* Returns NoSymbol otherwise. */
389+
def getPackageClassIfDefined(path: PreName): Symbol = {
390+
val name = path.toTypeName
391+
base.staticRef(name, isPackage = true, generateStubs = false)
392+
.requiredSymbol("package", name, generateStubs = false)(_ is PackageClass)
393+
}
394+
386395
def requiredModule(path: PreName): TermSymbol = {
387396
val name = path.toTermName
388397
base.staticRef(name).requiredSymbol("object", name)(_ is Module).asTerm

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package parsing
55
import scala.annotation.internal.sharable
66
import scala.collection.mutable.ListBuffer
77
import scala.collection.immutable.BitSet
8-
import util.{ SourceFile, SourcePosition }
8+
import util.{ SourceFile, SourcePosition, NoSourcePosition }
99
import Tokens._
1010
import Scanners._
1111
import xml.MarkupParsers.MarkupParser
@@ -473,8 +473,21 @@ object Parsers {
473473

474474
/* -------------- XML ---------------------------------------------------- */
475475

476-
/** the markup parser */
477-
lazy val xmlp: xml.MarkupParsers.MarkupParser = new MarkupParser(this, true)
476+
/** The markup parser.
477+
* The first time this lazy val is accessed, we assume we were trying to parse an XML literal.
478+
* The current position is recorded for later error reporting if it turns out
479+
* that we don't have scala-xml on the compilation classpath.
480+
*/
481+
lazy val xmlp: xml.MarkupParsers.MarkupParser = {
482+
myFirstXmlPos = source.atSpan(Span(in.offset))
483+
new MarkupParser(this, true)
484+
}
485+
486+
/** The position of the first XML literal encountered while parsing,
487+
* NoSourcePosition if there were no XML literals.
488+
*/
489+
def firstXmlPos: SourcePosition = myFirstXmlPos
490+
private[this] var myFirstXmlPos: SourcePosition = NoSourcePosition
478491

479492
object symbXMLBuilder extends xml.SymbolicXMLBuilder(this, true) // DEBUG choices
480493

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import parsing.Parsers.Parser
1111
import config.Config
1212
import config.Printers.{typr, default}
1313
import util.Stats._
14+
import util.{ SourcePosition, NoSourcePosition }
1415
import scala.util.control.NonFatal
1516
import ast.Trees._
1617

@@ -25,6 +26,11 @@ class FrontEnd extends Phase {
2526
/** The contexts for compilation units that are parsed but not yet entered */
2627
private[this] var remaining: List[Context] = Nil
2728

29+
/** The position of the first XML literal encountered while parsing,
30+
* NoSourcePosition if there were no XML literals.
31+
*/
32+
private[this] var firstXmlPos: SourcePosition = NoSourcePosition
33+
2834
/** Does a source file ending with `<name>.scala` belong to a compilation unit
2935
* that is parsed but not yet entered?
3036
*/
@@ -41,9 +47,17 @@ class FrontEnd extends Phase {
4147

4248
def parse(implicit ctx: Context): Unit = monitor("parsing") {
4349
val unit = ctx.compilationUnit
50+
4451
unit.untpdTree =
4552
if (unit.isJava) new JavaParser(unit.source).parse()
46-
else new Parser(unit.source).parse()
53+
else {
54+
val p = new Parser(unit.source)
55+
val tree = p.parse()
56+
if (p.firstXmlPos.exists && !firstXmlPos.exists)
57+
firstXmlPos = p.firstXmlPos
58+
tree
59+
}
60+
4761
val printer = if (ctx.settings.Xprint.value.contains("parser")) default else typr
4862
printer.println("parsed:\n" + unit.untpdTree.show)
4963
if (Config.checkPositions)
@@ -86,6 +100,12 @@ class FrontEnd extends Phase {
86100
enterSyms(remaining.head)
87101
remaining = remaining.tail
88102
}
103+
104+
if (firstXmlPos.exists && !defn.ScalaXmlPackageClass.exists)
105+
ctx.error("""To support XML literals, your project must depend on scala-xml.
106+
|See https://github.com/scala/scala-xml for more information.""".stripMargin,
107+
firstXmlPos)
108+
89109
unitContexts.foreach(typeCheck(_))
90110
record("total trees after typer", ast.Trees.ntrees)
91111
unitContexts.map(_.compilationUnit).filterNot(discardAfterTyper)

compiler/test/dotty/Properties.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,6 @@ object Properties {
5959
/** scala-asm jar */
6060
def scalaAsm: String = sys.props("dotty.tests.classes.scalaAsm")
6161

62-
/** scala-xml jar */
63-
def scalaXml: String = sys.props("dotty.tests.classes.scalaXml")
64-
6562
/** jline-terminal jar */
6663
def jlineTerminal: String = sys.props("dotty.tests.classes.jlineTerminal")
6764

compiler/test/dotty/tools/vulpix/TestConfiguration.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ object TestConfiguration {
1212
)
1313

1414
val checkOptions = Array(
15-
// "-Yscala2-unpickler", s"${Properties.scalaLibrary}:${Properties.scalaXml}",
15+
// "-Yscala2-unpickler", s"${Properties.scalaLibrary}",
1616
"-Yno-deep-subtypes",
1717
"-Yno-double-bindings",
1818
"-Yforce-sbt-phases",
@@ -21,13 +21,11 @@ object TestConfiguration {
2121

2222
val basicClasspath = mkClasspath(List(
2323
Properties.scalaLibrary,
24-
Properties.scalaXml,
2524
Properties.dottyLibrary
2625
))
2726

2827
val withCompilerClasspath = mkClasspath(List(
2928
Properties.scalaLibrary,
30-
Properties.scalaXml,
3129
Properties.scalaAsm,
3230
Properties.jlineTerminal,
3331
Properties.jlineReader,

project/Build.scala

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@ object Build {
6262
val referenceVersion = "0.15.0-RC1"
6363

6464
val baseVersion = "0.16.0"
65-
val baseSbtDottyVersion = "0.3.3"
65+
val baseSbtDottyVersion = "0.3.4"
6666

6767
// Versions used by the vscode extension to create a new project
6868
// This should be the latest published releases.
6969
// TODO: Have the vscode extension fetch these numbers from the Internet
7070
// instead of hardcoding them ?
7171
val publishedDottyVersion = referenceVersion
72-
val publishedSbtDottyVersion = "0.3.2"
72+
val publishedSbtDottyVersion = "0.3.3"
7373

7474

7575
val dottyOrganization = "ch.epfl.lamp"
@@ -294,7 +294,9 @@ object Build {
294294
dottyCompiler,
295295
allJars
296296
)
297-
}
297+
},
298+
// sbt-dotty defines `scalaInstance in doc` so we need to override it manually
299+
scalaInstance in doc := scalaInstance.value,
298300
)
299301

300302
lazy val commonBenchmarkSettings = Seq(
@@ -450,8 +452,6 @@ object Build {
450452
// get libraries onboard
451453
libraryDependencies ++= Seq(
452454
"org.scala-lang.modules" % "scala-asm" % "6.0.0-scala-1", // used by the backend
453-
// FIXME: Not needed, but should be on the compiler CP
454-
("org.scala-lang.modules" %% "scala-xml" % "1.1.0").withDottyCompat(scalaVersion.value),
455455
"org.scala-lang" % "scala-library" % scalacVersion % "test",
456456
Dependencies.`compiler-interface`,
457457
"org.jline" % "jline-reader" % "3.9.0", // used by the REPL
@@ -515,7 +515,6 @@ object Build {
515515
"-Ddotty.tests.classes.compilerInterface=" + findLib(attList, "compiler-interface"),
516516
"-Ddotty.tests.classes.scalaLibrary=" + findLib(attList, "scala-library-"),
517517
"-Ddotty.tests.classes.scalaAsm=" + findLib(attList, "scala-asm"),
518-
"-Ddotty.tests.classes.scalaXml=" + findLib(attList, "scala-xml"),
519518
"-Ddotty.tests.classes.jlineTerminal=" + findLib(attList, "jline-terminal"),
520519
"-Ddotty.tests.classes.jlineReader=" + findLib(attList, "jline-reader")
521520
)

sbt-bridge/src/xsbt/DelegatingReporter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ public void doReport(MessageContainer cont, Context ctx) {
8080
SourceFile src = pos.source();
8181
position = new Position() {
8282
public Optional<java.io.File> sourceFile() {
83-
if (src.exists()) return Optional.empty();
83+
if (!src.exists()) return Optional.empty();
8484
else return Optional.ofNullable(src.file().file());
8585
}
8686
public Optional<String> sourcePath() {
87-
if (src.exists()) return Optional.empty();
87+
if (!src.exists()) return Optional.empty();
8888
else return Optional.ofNullable(src.file().path());
8989
}
9090
public Optional<Integer> line() {

sbt-dotty/src/dotty/tools/sbtplugin/DottyPlugin.scala

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dotty.tools.sbtplugin
22

33
import sbt._
4+
import sbt.Def.Initialize
45
import sbt.Keys._
56
import sbt.librarymanagement.{
67
ivy, DependencyResolution, ScalaModuleInfo, SemanticSelector, UpdateConfiguration, UnresolvedWarningConfiguration,
@@ -171,20 +172,15 @@ object DottyPlugin extends AutoPlugin {
171172

172173
scalaCompilerBridgeBinaryJar := Def.settingDyn {
173174
if (isDotty.value) Def.task {
174-
val dottyBridgeArtifacts = fetchArtifactsOf(
175+
val updateReport = fetchArtifactsOf(
176+
scalaOrganization.value % "dotty-sbt-bridge" % scalaVersion.value,
175177
dependencyResolution.value,
176178
scalaModuleInfo.value,
177179
updateConfiguration.value,
178180
(unresolvedWarningConfiguration in update).value,
179181
streams.value.log,
180-
scalaOrganization.value % "dotty-sbt-bridge" % scalaVersion.value).allFiles
181-
val jars = dottyBridgeArtifacts.filter(art => art.getName.startsWith("dotty-sbt-bridge") && art.getName.endsWith(".jar")).toArray
182-
if (jars.size == 0)
183-
throw new MessageOnlyException("No jar found for dotty-sbt-bridge")
184-
else if (jars.size > 1)
185-
throw new MessageOnlyException(s"Multiple jars found for dotty-sbt-bridge: ${jars.toList}")
186-
else
187-
jars.headOption
182+
)
183+
Option(getJar(updateReport, scalaOrganization.value, "dotty-sbt-bridge", scalaVersion.value))
188184
}
189185
else Def.task {
190186
None: Option[File]
@@ -289,39 +285,20 @@ object DottyPlugin extends AutoPlugin {
289285
},
290286
// ... instead, we'll fetch the compiler and its dependencies ourselves.
291287
scalaInstance := Def.taskDyn {
292-
if (isDotty.value) Def.task {
293-
val updateReport =
294-
fetchArtifactsOf(
295-
dependencyResolution.value,
296-
scalaModuleInfo.value,
297-
updateConfiguration.value,
298-
(unresolvedWarningConfiguration in update).value,
299-
streams.value.log,
300-
scalaOrganization.value %% "dotty-doc" % scalaVersion.value)
301-
val scalaLibraryJar = getJar(updateReport,
302-
"org.scala-lang", "scala-library", revision = AllPassFilter)
303-
val dottyLibraryJar = getJar(updateReport,
304-
scalaOrganization.value, s"dotty-library_${scalaBinaryVersion.value}", scalaVersion.value)
305-
val compilerJar = getJar(updateReport,
306-
scalaOrganization.value, s"dotty-compiler_${scalaBinaryVersion.value}", scalaVersion.value)
307-
val allJars =
308-
getJars(updateReport, AllPassFilter, AllPassFilter, AllPassFilter)
309-
310-
makeScalaInstance(
311-
state.value,
312-
scalaVersion.value,
313-
scalaLibraryJar,
314-
dottyLibraryJar,
315-
compilerJar,
316-
allJars
317-
)
318-
}
288+
if (isDotty.value)
289+
dottyScalaInstanceTask("dotty-compiler")
319290
else
320-
// This dereferences the Initialize graph, but keeps the Task unevaluated,
321-
// so its effect gets fired only when isDotty.value evaluates to false. yay monad.
322291
Def.valueStrict { scalaInstance.taskValue }
323292
}.value,
324293

294+
// We need more stuff on the classpath to run the `doc` task.
295+
scalaInstance in doc := Def.taskDyn {
296+
if (isDotty.value)
297+
dottyScalaInstanceTask("dotty-doc")
298+
else
299+
Def.valueStrict { (scalaInstance in doc).taskValue }
300+
}.value,
301+
325302
// Because managedScalaInstance is false, sbt won't add the standard library to our dependencies for us
326303
libraryDependencies ++= {
327304
if (isDotty.value && autoScalaLibrary.value)
@@ -355,6 +332,7 @@ object DottyPlugin extends AutoPlugin {
355332
old
356333
}
357334
}.value,
335+
358336
scalacOptions ++= {
359337
if (isDotty.value) {
360338
val projectName =
@@ -369,17 +347,17 @@ object DottyPlugin extends AutoPlugin {
369347
}
370348
else
371349
Seq()
372-
}
350+
},
373351
))
374352

375353
/** Fetch artifacts for moduleID */
376354
def fetchArtifactsOf(
355+
moduleID: ModuleID,
377356
dependencyRes: DependencyResolution,
378357
scalaInfo: Option[ScalaModuleInfo],
379358
updateConfig: UpdateConfiguration,
380359
warningConfig: UnresolvedWarningConfiguration,
381-
log: Logger,
382-
moduleID: ModuleID): UpdateReport = {
360+
log: Logger): UpdateReport = {
383361
val descriptor = dependencyRes.wrapDependencyInModule(moduleID, scalaInfo)
384362

385363
dependencyRes.update(descriptor, updateConfig, warningConfig, log) match {
@@ -396,18 +374,48 @@ object DottyPlugin extends AutoPlugin {
396374
updateReport.select(
397375
configurationFilter(Runtime.name),
398376
moduleFilter(organization, name, revision),
399-
artifactFilter(extension = "jar")
377+
artifactFilter(extension = "jar", classifier = "")
400378
)
401379
}
402380

403381
/** Get the single jar in updateReport that match the given filter.
404-
* If zero or more than one jar match, an exception will be thrown. */
382+
* If zero or more than one jar match, an exception will be thrown.
383+
*/
405384
def getJar(updateReport: UpdateReport, organization: NameFilter, name: NameFilter, revision: NameFilter): File = {
406385
val jars = getJars(updateReport, organization, name, revision)
407386
assert(jars.size == 1, s"There should only be one $name jar but found: $jars")
408387
jars.head
409388
}
410389

390+
/** Create a scalaInstance task that uses Dotty based on `moduleName`. */
391+
def dottyScalaInstanceTask(moduleName: String): Initialize[Task[ScalaInstance]] = Def.task {
392+
val updateReport =
393+
fetchArtifactsOf(
394+
scalaOrganization.value %% moduleName % scalaVersion.value,
395+
dependencyResolution.value,
396+
scalaModuleInfo.value,
397+
updateConfiguration.value,
398+
(unresolvedWarningConfiguration in update).value,
399+
streams.value.log)
400+
val scalaLibraryJar = getJar(updateReport,
401+
"org.scala-lang", "scala-library", revision = AllPassFilter)
402+
val dottyLibraryJar = getJar(updateReport,
403+
scalaOrganization.value, s"dotty-library_${scalaBinaryVersion.value}", scalaVersion.value)
404+
val compilerJar = getJar(updateReport,
405+
scalaOrganization.value, s"dotty-compiler_${scalaBinaryVersion.value}", scalaVersion.value)
406+
val allJars =
407+
getJars(updateReport, AllPassFilter, AllPassFilter, AllPassFilter)
408+
409+
makeScalaInstance(
410+
state.value,
411+
scalaVersion.value,
412+
scalaLibraryJar,
413+
dottyLibraryJar,
414+
compilerJar,
415+
allJars
416+
)
417+
}
418+
411419
def makeScalaInstance(
412420
state: State, dottyVersion: String, scalaLibrary: File, dottyLibrary: File, compiler: File, all: Seq[File]
413421
): ScalaInstance = {

tests/neg/xml.check

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- Error: tests/neg/xml.scala:2:10 -------------------------------------------------------------------------------------
2+
2 | val a = <foo>bla</foo> // error // error
3+
| ^
4+
| To support XML literals, your project must depend on scala-xml.
5+
| See https://github.com/scala/scala-xml for more information.
6+
-- [E008] Member Not Found Error: tests/neg/xml.scala:2:11 -------------------------------------------------------------
7+
2 | val a = <foo>bla</foo> // error // error
8+
| ^
9+
| value xml is not a member of scala - did you mean scala.&?

0 commit comments

Comments
 (0)