Skip to content

Fix #5597: Remove scala-xml dependency, add it to the community-build #6595

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@
[submodule "community-build/community-projects/sourcecode"]
path = community-build/community-projects/sourcecode
url = https://github.com/dotty-staging/sourcecode
[submodule "community-build/community-projects/scala-xml"]
path = community-build/community-projects/scala-xml
url = https://github.com/scala/scala-xml
1 change: 1 addition & 0 deletions community-build/community-projects/scala-xml
Submodule scala-xml added at 19f53a
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ class CommunityBuildTest {
updateCommand = "scalatest/update"
)

@Test def scalaXml = test(
project = "scala-xml",
testCommand = "xml/test",
updateCommand = "xml/update"
)

@Test def scopt = test(
project = "scopt",
testCommand = "scoptJVM/compile",
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ class Definitions {
lazy val Sys_errorR: TermRef = SysPackage.moduleClass.requiredMethodRef(nme.error)
def Sys_error(implicit ctx: Context): Symbol = Sys_errorR.symbol

lazy val ScalaXmlPackageClass: Symbol = ctx.getPackageClassIfDefined("scala.xml")

lazy val CompiletimePackageObjectRef: TermRef = ctx.requiredModuleRef("scala.compiletime.package")
lazy val CompiletimePackageObject: Symbol = CompiletimePackageObjectRef.symbol.moduleClass
lazy val Compiletime_errorR: TermRef = CompiletimePackageObjectRef.symbol.requiredMethodRef(nme.error)
Expand Down
9 changes: 9 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,15 @@ trait Symbols { this: Context =>
.requiredSymbol("class", name, generateStubs = false)(_.isClass)
}

/** Get ClassSymbol if package is either defined in current compilation run
* or present on classpath.
* Returns NoSymbol otherwise. */
def getPackageClassIfDefined(path: PreName): Symbol = {
val name = path.toTypeName
base.staticRef(name, isPackage = true, generateStubs = false)
.requiredSymbol("package", name, generateStubs = false)(_ is PackageClass)
}

def requiredModule(path: PreName): TermSymbol = {
val name = path.toTermName
base.staticRef(name).requiredSymbol("object", name)(_ is Module).asTerm
Expand Down
19 changes: 16 additions & 3 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package parsing
import scala.annotation.internal.sharable
import scala.collection.mutable.ListBuffer
import scala.collection.immutable.BitSet
import util.{ SourceFile, SourcePosition }
import util.{ SourceFile, SourcePosition, NoSourcePosition }
import Tokens._
import Scanners._
import xml.MarkupParsers.MarkupParser
Expand Down Expand Up @@ -473,8 +473,21 @@ object Parsers {

/* -------------- XML ---------------------------------------------------- */

/** the markup parser */
lazy val xmlp: xml.MarkupParsers.MarkupParser = new MarkupParser(this, true)
/** The markup parser.
* The first time this lazy val is accessed, we assume we were trying to parse an XML literal.
* The current position is recorded for later error reporting if it turns out
* that we don't have scala-xml on the compilation classpath.
*/
lazy val xmlp: xml.MarkupParsers.MarkupParser = {
myFirstXmlPos = source.atSpan(Span(in.offset))
new MarkupParser(this, true)
}

/** The position of the first XML literal encountered while parsing,
* NoSourcePosition if there were no XML literals.
*/
def firstXmlPos: SourcePosition = myFirstXmlPos
private[this] var myFirstXmlPos: SourcePosition = NoSourcePosition

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

Expand Down
22 changes: 21 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/FrontEnd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import parsing.Parsers.Parser
import config.Config
import config.Printers.{typr, default}
import util.Stats._
import util.{ SourcePosition, NoSourcePosition }
import scala.util.control.NonFatal
import ast.Trees._

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

/** The position of the first XML literal encountered while parsing,
* NoSourcePosition if there were no XML literals.
*/
private[this] var firstXmlPos: SourcePosition = NoSourcePosition

/** Does a source file ending with `<name>.scala` belong to a compilation unit
* that is parsed but not yet entered?
*/
Expand All @@ -41,9 +47,17 @@ class FrontEnd extends Phase {

def parse(implicit ctx: Context): Unit = monitor("parsing") {
val unit = ctx.compilationUnit

unit.untpdTree =
if (unit.isJava) new JavaParser(unit.source).parse()
else new Parser(unit.source).parse()
else {
val p = new Parser(unit.source)
val tree = p.parse()
if (p.firstXmlPos.exists && !firstXmlPos.exists)
firstXmlPos = p.firstXmlPos
tree
}

val printer = if (ctx.settings.Xprint.value.contains("parser")) default else typr
printer.println("parsed:\n" + unit.untpdTree.show)
if (Config.checkPositions)
Expand Down Expand Up @@ -86,6 +100,12 @@ class FrontEnd extends Phase {
enterSyms(remaining.head)
remaining = remaining.tail
}

if (firstXmlPos.exists && !defn.ScalaXmlPackageClass.exists)
ctx.error("""To support XML literals, your project must depend on scala-xml.
|See https://github.com/scala/scala-xml for more information.""".stripMargin,
firstXmlPos)

unitContexts.foreach(typeCheck(_))
record("total trees after typer", ast.Trees.ntrees)
unitContexts.map(_.compilationUnit).filterNot(discardAfterTyper)
Expand Down
3 changes: 0 additions & 3 deletions compiler/test/dotty/Properties.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ object Properties {
/** scala-asm jar */
def scalaAsm: String = sys.props("dotty.tests.classes.scalaAsm")

/** scala-xml jar */
def scalaXml: String = sys.props("dotty.tests.classes.scalaXml")

/** jline-terminal jar */
def jlineTerminal: String = sys.props("dotty.tests.classes.jlineTerminal")

Expand Down
4 changes: 1 addition & 3 deletions compiler/test/dotty/tools/vulpix/TestConfiguration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object TestConfiguration {
)

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

val basicClasspath = mkClasspath(List(
Properties.scalaLibrary,
Properties.scalaXml,
Properties.dottyLibrary
))

val withCompilerClasspath = mkClasspath(List(
Properties.scalaLibrary,
Properties.scalaXml,
Properties.scalaAsm,
Properties.jlineTerminal,
Properties.jlineReader,
Expand Down
11 changes: 5 additions & 6 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ object Build {
val referenceVersion = "0.15.0-RC1"

val baseVersion = "0.16.0"
val baseSbtDottyVersion = "0.3.3"
val baseSbtDottyVersion = "0.3.4"

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


val dottyOrganization = "ch.epfl.lamp"
Expand Down Expand Up @@ -294,7 +294,9 @@ object Build {
dottyCompiler,
allJars
)
}
},
// sbt-dotty defines `scalaInstance in doc` so we need to override it manually
scalaInstance in doc := scalaInstance.value,
)

lazy val commonBenchmarkSettings = Seq(
Expand Down Expand Up @@ -450,8 +452,6 @@ object Build {
// get libraries onboard
libraryDependencies ++= Seq(
"org.scala-lang.modules" % "scala-asm" % "6.0.0-scala-1", // used by the backend
// FIXME: Not needed, but should be on the compiler CP
("org.scala-lang.modules" %% "scala-xml" % "1.1.0").withDottyCompat(scalaVersion.value),
"org.scala-lang" % "scala-library" % scalacVersion % "test",
Dependencies.`compiler-interface`,
"org.jline" % "jline-reader" % "3.9.0", // used by the REPL
Expand Down Expand Up @@ -515,7 +515,6 @@ object Build {
"-Ddotty.tests.classes.compilerInterface=" + findLib(attList, "compiler-interface"),
"-Ddotty.tests.classes.scalaLibrary=" + findLib(attList, "scala-library-"),
"-Ddotty.tests.classes.scalaAsm=" + findLib(attList, "scala-asm"),
"-Ddotty.tests.classes.scalaXml=" + findLib(attList, "scala-xml"),
"-Ddotty.tests.classes.jlineTerminal=" + findLib(attList, "jline-terminal"),
"-Ddotty.tests.classes.jlineReader=" + findLib(attList, "jline-reader")
)
Expand Down
4 changes: 2 additions & 2 deletions sbt-bridge/src/xsbt/DelegatingReporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ public void doReport(MessageContainer cont, Context ctx) {
SourceFile src = pos.source();
position = new Position() {
public Optional<java.io.File> sourceFile() {
if (src.exists()) return Optional.empty();
if (!src.exists()) return Optional.empty();
else return Optional.ofNullable(src.file().file());
}
public Optional<String> sourcePath() {
if (src.exists()) return Optional.empty();
if (!src.exists()) return Optional.empty();
else return Optional.ofNullable(src.file().path());
}
public Optional<Integer> line() {
Expand Down
94 changes: 51 additions & 43 deletions sbt-dotty/src/dotty/tools/sbtplugin/DottyPlugin.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dotty.tools.sbtplugin

import sbt._
import sbt.Def.Initialize
import sbt.Keys._
import sbt.librarymanagement.{
ivy, DependencyResolution, ScalaModuleInfo, SemanticSelector, UpdateConfiguration, UnresolvedWarningConfiguration,
Expand Down Expand Up @@ -171,20 +172,15 @@ object DottyPlugin extends AutoPlugin {

scalaCompilerBridgeBinaryJar := Def.settingDyn {
if (isDotty.value) Def.task {
val dottyBridgeArtifacts = fetchArtifactsOf(
val updateReport = fetchArtifactsOf(
scalaOrganization.value % "dotty-sbt-bridge" % scalaVersion.value,
dependencyResolution.value,
scalaModuleInfo.value,
updateConfiguration.value,
(unresolvedWarningConfiguration in update).value,
streams.value.log,
scalaOrganization.value % "dotty-sbt-bridge" % scalaVersion.value).allFiles
val jars = dottyBridgeArtifacts.filter(art => art.getName.startsWith("dotty-sbt-bridge") && art.getName.endsWith(".jar")).toArray
if (jars.size == 0)
throw new MessageOnlyException("No jar found for dotty-sbt-bridge")
else if (jars.size > 1)
throw new MessageOnlyException(s"Multiple jars found for dotty-sbt-bridge: ${jars.toList}")
else
jars.headOption
)
Option(getJar(updateReport, scalaOrganization.value, "dotty-sbt-bridge", scalaVersion.value))
}
else Def.task {
None: Option[File]
Expand Down Expand Up @@ -289,39 +285,20 @@ object DottyPlugin extends AutoPlugin {
},
// ... instead, we'll fetch the compiler and its dependencies ourselves.
scalaInstance := Def.taskDyn {
if (isDotty.value) Def.task {
val updateReport =
fetchArtifactsOf(
dependencyResolution.value,
scalaModuleInfo.value,
updateConfiguration.value,
(unresolvedWarningConfiguration in update).value,
streams.value.log,
scalaOrganization.value %% "dotty-doc" % scalaVersion.value)
val scalaLibraryJar = getJar(updateReport,
"org.scala-lang", "scala-library", revision = AllPassFilter)
val dottyLibraryJar = getJar(updateReport,
scalaOrganization.value, s"dotty-library_${scalaBinaryVersion.value}", scalaVersion.value)
val compilerJar = getJar(updateReport,
scalaOrganization.value, s"dotty-compiler_${scalaBinaryVersion.value}", scalaVersion.value)
val allJars =
getJars(updateReport, AllPassFilter, AllPassFilter, AllPassFilter)

makeScalaInstance(
state.value,
scalaVersion.value,
scalaLibraryJar,
dottyLibraryJar,
compilerJar,
allJars
)
}
if (isDotty.value)
dottyScalaInstanceTask("dotty-compiler")
else
// This dereferences the Initialize graph, but keeps the Task unevaluated,
// so its effect gets fired only when isDotty.value evaluates to false. yay monad.
Def.valueStrict { scalaInstance.taskValue }
}.value,

// We need more stuff on the classpath to run the `doc` task.
scalaInstance in doc := Def.taskDyn {
if (isDotty.value)
dottyScalaInstanceTask("dotty-doc")
else
Def.valueStrict { (scalaInstance in doc).taskValue }
}.value,

// Because managedScalaInstance is false, sbt won't add the standard library to our dependencies for us
libraryDependencies ++= {
if (isDotty.value && autoScalaLibrary.value)
Expand Down Expand Up @@ -355,6 +332,7 @@ object DottyPlugin extends AutoPlugin {
old
}
}.value,

scalacOptions ++= {
if (isDotty.value) {
val projectName =
Expand All @@ -369,17 +347,17 @@ object DottyPlugin extends AutoPlugin {
}
else
Seq()
}
},
))

/** Fetch artifacts for moduleID */
def fetchArtifactsOf(
moduleID: ModuleID,
dependencyRes: DependencyResolution,
scalaInfo: Option[ScalaModuleInfo],
updateConfig: UpdateConfiguration,
warningConfig: UnresolvedWarningConfiguration,
log: Logger,
moduleID: ModuleID): UpdateReport = {
log: Logger): UpdateReport = {
val descriptor = dependencyRes.wrapDependencyInModule(moduleID, scalaInfo)

dependencyRes.update(descriptor, updateConfig, warningConfig, log) match {
Expand All @@ -396,18 +374,48 @@ object DottyPlugin extends AutoPlugin {
updateReport.select(
configurationFilter(Runtime.name),
moduleFilter(organization, name, revision),
artifactFilter(extension = "jar")
artifactFilter(extension = "jar", classifier = "")
)
}

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

/** Create a scalaInstance task that uses Dotty based on `moduleName`. */
def dottyScalaInstanceTask(moduleName: String): Initialize[Task[ScalaInstance]] = Def.task {
val updateReport =
fetchArtifactsOf(
scalaOrganization.value %% moduleName % scalaVersion.value,
dependencyResolution.value,
scalaModuleInfo.value,
updateConfiguration.value,
(unresolvedWarningConfiguration in update).value,
streams.value.log)
val scalaLibraryJar = getJar(updateReport,
"org.scala-lang", "scala-library", revision = AllPassFilter)
val dottyLibraryJar = getJar(updateReport,
scalaOrganization.value, s"dotty-library_${scalaBinaryVersion.value}", scalaVersion.value)
val compilerJar = getJar(updateReport,
scalaOrganization.value, s"dotty-compiler_${scalaBinaryVersion.value}", scalaVersion.value)
val allJars =
getJars(updateReport, AllPassFilter, AllPassFilter, AllPassFilter)

makeScalaInstance(
state.value,
scalaVersion.value,
scalaLibraryJar,
dottyLibraryJar,
compilerJar,
allJars
)
}

def makeScalaInstance(
state: State, dottyVersion: String, scalaLibrary: File, dottyLibrary: File, compiler: File, all: Seq[File]
): ScalaInstance = {
Expand Down
9 changes: 9 additions & 0 deletions tests/neg/xml.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Error: tests/neg/xml.scala:2:10 -------------------------------------------------------------------------------------
2 | val a = <foo>bla</foo> // error // error
| ^
| To support XML literals, your project must depend on scala-xml.
| See https://github.com/scala/scala-xml for more information.
-- [E008] Member Not Found Error: tests/neg/xml.scala:2:11 -------------------------------------------------------------
2 | val a = <foo>bla</foo> // error // error
| ^
| value xml is not a member of scala - did you mean scala.&?
Loading