diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-01-22 00:33:18 +0100 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-06-20 15:46:26 -0700 |
commit | 9b72669a076206f1edbe34464717375c97997cea (patch) | |
tree | 9b62ed2461f2e06e289c504b14d38a757ae02801 | |
parent | 4e9b33ab24bb3bf922c37a05a79af364b7b32b84 (diff) | |
download | scala-9b72669a076206f1edbe34464717375c97997cea.tar.gz scala-9b72669a076206f1edbe34464717375c97997cea.tar.bz2 scala-9b72669a076206f1edbe34464717375c97997cea.zip |
Set scene for Predef.$scope's demise.
When there's no Predef.$scope but xml is being used,
the compiler aliases scala.xml.TopScope to $scope.
There must be a scala.xml package when xml literals were parsed.
For compatibility with the old library, which relied on $scope being in scope,
synthesize a `import scala.xml.{TopScope => $scope}` when xml is needed,
but there's no Predef.$scope and the old library is detected (scala.xml.TopScope exists).
-rw-r--r-- | src/compiler/scala/tools/nsc/CompilationUnits.scala | 14 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/TreeGen.scala | 19 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 13 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 26 | ||||
-rw-r--r-- | src/library/scala/Predef.scala | 8 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Definitions.scala | 6 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Mirrors.scala | 3 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/StdNames.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Trees.scala | 2 |
9 files changed, 80 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 15d365ab8c..b52e6fdf57 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -34,6 +34,20 @@ trait CompilationUnits { self: Global => /** the content of the compilation unit in tree form */ var body: Tree = EmptyTree + /** The position of the first xml literal encountered while parsing this compilation unit. + * NoPosition if there were none. Write-once. + */ + private[this] var _firstXmlPos: Position = NoPosition + + /** Record that we encountered XML. Should only be called once. */ + protected[nsc] def encounteredXml(pos: Position) = _firstXmlPos = pos + + /** Does this unit contain XML? */ + def hasXml = _firstXmlPos ne NoPosition + + /** Position of first XML literal in this unit. */ + def firstXmlPos = _firstXmlPos + def exists = source != NoSourceFile && source != null /** Note: depends now contains toplevel classes. diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 692afbac66..c28a6ba337 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -19,11 +19,20 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { import global._ import definitions._ - /** Builds a fully attributed wildcard import node. + /** Builds a fully attributed, synthetic wildcard import node. */ - def mkWildcardImport(pkg: Symbol): Import = { - assert(pkg ne null, this) - val qual = gen.mkAttributedStableRef(pkg) + def mkWildcardImport(pkg: Symbol): Import = + mkImportFromSelector(pkg, ImportSelector.wildList) + + /** Builds a fully attributed, synthetic import node. + * import `qualSym`.{`name` => `toName`} + */ + def mkImport(qualSym: Symbol, name: Name, toName: Name): Import = + mkImportFromSelector(qualSym, ImportSelector(name, 0, toName, 0) :: Nil) + + private def mkImportFromSelector(qualSym: Symbol, selector: List[ImportSelector]): Import = { + assert(qualSym ne null, this) + val qual = gen.mkAttributedStableRef(qualSym) val importSym = ( NoSymbol newImport NoPosition @@ -31,7 +40,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { setInfo analyzer.ImportType(qual) ) val importTree = ( - Import(qual, ImportSelector.wildList) + Import(qual, selector) setSymbol importSym setType NoType ) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index fc532f5d44..ef5872986c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -166,13 +166,20 @@ self => def syntaxError(offset: Int, msg: String): Unit = throw new MalformedInput(offset, msg) def incompleteInputError(msg: String): Unit = throw new MalformedInput(source.content.length - 1, msg) - /** the markup parser */ - lazy val xmlp = new MarkupParser(this, preserveWS = true) - object symbXMLBuilder extends SymbolicXMLBuilder(this, preserveWS = true) { // DEBUG choices val global: self.global.type = self.global } + /** 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 the xml library on the compilation classpath. + */ + private[this] lazy val xmlp = { + currentUnit.encounteredXml(o2p(in.offset)) + new MarkupParser(this, preserveWS = true) + } + def xmlLiteral() : Tree = xmlp.xLiteral def xmlLiteralPattern() : Tree = xmlp.xLiteralPattern } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 61967d4cee..1f4ff7cc2d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -16,7 +16,7 @@ import scala.reflect.internal.util.shortClassOfInstance */ trait Contexts { self: Analyzer => import global._ - import definitions.{ JavaLangPackage, ScalaPackage, PredefModule } + import definitions.{ JavaLangPackage, ScalaPackage, PredefModule, ScalaXmlTopScope, ScalaXmlPackage } import ContextMode._ object NoContext @@ -93,9 +93,31 @@ trait Contexts { self: Analyzer => else RootImports.completeList } + def rootContext(unit: CompilationUnit, tree: Tree = EmptyTree, erasedTypes: Boolean = false): Context = { val rootImportsContext = (startContext /: rootImports(unit))((c, sym) => c.make(gen.mkWildcardImport(sym))) - val c = rootImportsContext.make(tree, unit = unit) + + // there must be a scala.xml package when xml literals were parsed in this unit + if (unit.hasXml && ScalaXmlPackage == NoSymbol) + unit.error(unit.firstXmlPos, "XML literals may only be used if the package scala.xml is present in the compilation classpath.") + + // TODO: remove the def below and drop `|| predefDefinesDollarScope` in the condition for `contextWithXML` + // as soon as 2.11.0-M4 is released and used as STARR (and $scope is no longer defined in Predef) + // Until then, to allow compiling quick with pre-2.11.0-M4 STARR, + // which relied on Predef defining `val $scope`, we've left it in place. + // Since the new scheme also imports $scope (as an alias for scala.xml.TopScope), + // we must check whether it is still there and not import the alias to avoid ambiguity. + // (All of this is only necessary to compile the full quick stage with STARR. + // if using locker, Predef.$scope is no longer needed.) + def predefDefinesDollarScope = definitions.getMemberIfDefined(PredefModule, nme.dollarScope) != NoSymbol + + // hack for the old xml library (detected by looking for scala.xml.TopScope, which needs to be in scope as $scope) + // import scala.xml.{TopScope => $scope} + val contextWithXML = + if (!unit.hasXml || ScalaXmlTopScope == NoSymbol || predefDefinesDollarScope) rootImportsContext + else rootImportsContext.make(gen.mkImport(ScalaXmlPackage, nme.TopScope, nme.dollarScope)) + + val c = contextWithXML.make(tree, unit = unit) if (erasedTypes) c.setThrowErrors() else c.setReportErrors() c(EnrichmentEnabled | ImplicitsEnabled) = !erasedTypes c diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 5ba38600b6..a188602543 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -134,7 +134,13 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { @inline def implicitly[T](implicit e: T) = e // for summoning implicit values from the nether world -- TODO: when dependent method types are on by default, give this result type `e.type`, so that inliner has better chance of knowing which method to inline in calls like `implicitly[MatchingStrategy[Option]].zero` @inline def locally[T](x: T): T = x // to communicate intent and avoid unmoored statements - // Apparently needed for the xml library + // TODO: remove `val $scope = ...` as soon as 2.11.0-M4 is released and used as STARR + // As it has a '$' in its name, we don't have to deprecate first. + // The compiler now aliases `scala.xml.TopScope` to `$scope` (unless Predef.$scope is still there). + // This definition left in place for older compilers and to compile quick with pre-2.11.0-M4 STARR. + // In principle we don't need it to compile library/reflect/compiler (there's no xml left there), + // so a new locker can be built without this definition, and locker can build quick + // (partest, scaladoc still require xml). val $scope = scala.xml.TopScope // errors and asserts ------------------------------------------------- diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 4f2b7e2642..3470b05495 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -16,7 +16,7 @@ import scala.reflect.api.{Universe => ApiUniverse} trait Definitions extends api.StandardDefinitions { self: SymbolTable => - import rootMirror.{getModule, getPackage, getClassByName, getRequiredClass, getRequiredModule, getClassIfDefined, getModuleIfDefined, getPackageObject, getPackageObjectIfDefined, requiredClass, requiredModule} + import rootMirror.{getModule, getPackage, getClassByName, getRequiredClass, getRequiredModule, getClassIfDefined, getModuleIfDefined, getPackageObject, getPackageIfDefined, getPackageObjectIfDefined, requiredClass, requiredModule} object definitions extends DefinitionsClass @@ -471,6 +471,10 @@ trait Definitions extends api.StandardDefinitions { def methodCache_find = getMemberMethod(MethodCacheClass, nme.find_) def methodCache_add = getMemberMethod(MethodCacheClass, nme.add_) + // XML + lazy val ScalaXmlTopScope = getModuleIfDefined("scala.xml.TopScope") + lazy val ScalaXmlPackage = getPackageIfDefined("scala.xml") + // scala.reflect lazy val ReflectPackage = requiredModule[scala.reflect.`package`.type] lazy val ReflectApiPackage = getPackageObjectIfDefined("scala.reflect.api") // defined in scala-reflect.jar, so we need to be careful diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index bf38c3bf1e..6ed9de8e20 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -176,6 +176,9 @@ trait Mirrors extends api.Mirrors { def getPackage(fullname: TermName): ModuleSymbol = ensurePackageSymbol(fullname.toString, getModuleOrClass(fullname), allowModules = true) + def getPackageIfDefined(fullname: TermName): Symbol = + wrapMissing(getPackage(fullname)) + @deprecated("Use getPackage", "2.11.0") def getRequiredPackage(fullname: String): ModuleSymbol = getPackage(newTermNameCached(fullname)) diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 81fffc833c..30aaaa1f3a 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -599,6 +599,7 @@ trait StdNames { val currentMirror: NameType = "currentMirror" val delayedInit: NameType = "delayedInit" val delayedInitArg: NameType = "delayedInit$body" + val dollarScope: NameType = "$scope" val drop: NameType = "drop" val elem: NameType = "elem" val emptyValDef: NameType = "emptyValDef" @@ -684,6 +685,7 @@ trait StdNames { val thisPrefix : NameType = "thisPrefix" val toArray: NameType = "toArray" val toObjectArray : NameType = "toObjectArray" + val TopScope: NameType = "TopScope" val toString_ : NameType = "toString" val toTypeConstructor: NameType = "toTypeConstructor" val tpe : NameType = "tpe" diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 8781423a6d..ceb3b383d7 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -327,7 +327,7 @@ trait Trees extends api.Trees { self: SymbolTable => case class ImportSelector(name: Name, namePos: Int, rename: Name, renamePos: Int) extends ImportSelectorApi object ImportSelector extends ImportSelectorExtractor { val wild = ImportSelector(nme.WILDCARD, -1, null, -1) - val wildList = List(wild) + val wildList = List(wild) // OPT This list is shared for performance. } case class Import(expr: Tree, selectors: List[ImportSelector]) |