summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorSean McDirmid <sean.mcdirmid@gmail.com>2006-01-11 08:04:06 +0000
committerSean McDirmid <sean.mcdirmid@gmail.com>2006-01-11 08:04:06 +0000
commitcfd33de80751bc0d3d4c80c140a78de0e1201c2e (patch)
tree86f2dfa3d11aff1180b94ffdfef1441cdb87ba12 /src/compiler
parent5dfb1f07ada2698ed8e3078c820d0f8c47e1b21b (diff)
downloadscala-cfd33de80751bc0d3d4c80c140a78de0e1201c2e.tar.gz
scala-cfd33de80751bc0d3d4c80c140a78de0e1201c2e.tar.bz2
scala-cfd33de80751bc0d3d4c80c140a78de0e1201c2e.zip
More stuff to support hte eclipse plugin.
* Added symbol positions to to the pickler. * Deprecated util/ClassPath.java to use ClassPath.scala, which allows for source attachments. -- maybe we should remove ClassPath.java since it is no longer used. * Added support for content outline.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala12
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala6
-rw-r--r--src/compiler/scala/tools/nsc/models/Models.scala (renamed from src/compiler/scala/tools/nsc/models/Models.scala.xxx)165
-rw-r--r--src/compiler/scala/tools/nsc/models/SemanticTokens.scala22
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala137
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala9
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala10
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala18
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala28
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala211
-rw-r--r--src/compiler/scala/tools/nsc/util/Position.scala14
-rw-r--r--src/compiler/scala/tools/util/ZipArchive.java2
13 files changed, 468 insertions, 168 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 3e1ce5bf50..c7a4b2926b 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -7,7 +7,8 @@ package scala.tools.nsc;
import java.io._;
import java.nio.charset._;
-import scala.tools.util.{SourceReader,ClassPath,AbstractFile};
+import scala.tools.util.{SourceReader,AbstractFile};
+import scala.tools.nsc.util.ClassPath;
import scala.tools.nsc.util.{Position,SourceFile};
import scala.tools.nsc.reporters._;
@@ -116,9 +117,10 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
new SourceReader(charset.newDecoder());
}
- val classPath = new ClassPath(
+ val classPath = new ClassPath.Build(
settings.classpath.value,
settings.sourcepath.value,
+ settings.outdir.value,
settings.bootclasspath.value,
settings.extdirs.value);
@@ -137,7 +139,9 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
}
def getSourceFile(clazz: Symbol): SourceFile = {
- val f = classPath.getRoot().lookupPath(
+ val f = classPath.output.source.location.
+ /* val f = classPath.getRoot(). */
+ lookupPath(
clazz.fullNameString(File.separatorChar) + ".scala", false);
if (f == null) throw new FileNotFoundException(
"source file for " + clazz + " could not be found");
@@ -148,7 +152,7 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
val global: Global.this.type = Global.this
}
- def rootLoader: LazyType = new loaders.PackageLoader(classPath.getRoot());
+ def rootLoader: LazyType = new loaders.PackageLoader(classPath.root /* getRoot() */);
val migrateMsg = "migration problem when moving from Scala version 1.0 to version 2.0:\n";
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index bd853d3f93..78c1dd7365 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -20,6 +20,8 @@ mixin class Trees requires Global {
def isPrivate = ((flags & PRIVATE ) != 0);
def isProtected = ((flags & PROTECTED) != 0);
def isVariable = ((flags & MUTABLE ) != 0);
+ def isArgument = ((flags & PARAM ) != 0);
+ def isAccessor = ((flags & ACCESSOR ) != 0);
def isPublic = !isPrivate && !isProtected;
def hasFlag(flag: int) = (flags & flag) != 0;
def | (flag: int): Modifiers = {
@@ -141,7 +143,6 @@ mixin class Trees requires Global {
assert(keyword != null);
if (!source.beginsWith(pos, keyword + " ")) {
val p = new Position(source, pos);
- // System.err.println("SYM=" + symbol + " KW=" + keyword + " LINE=" + p.lineContent + " TEXT=" + source.content(pos) + source.content(pos + 1));
if (true) return Position.NOPOS;
else throw new Error();
}
@@ -214,7 +215,8 @@ mixin class Trees requires Global {
def keyword = if (mods.isVariable) "var" else "val";
override def namePos(source : SourceFile) =
if (pos == Position.NOPOS) Position.NOPOS;
- else if (source.beginsWith(pos, "val ") || source.beginsWith(pos, "var ")) source.skipWhitespace(pos + ("val ").length());
+ else if (source.beginsWith(pos, "val ") || source.beginsWith(pos, "var "))
+ source.skipWhitespace(pos + ("val ").length());
else if (source.content(pos) == ',') source.skipWhitespace(pos + 1);
else pos;
}
diff --git a/src/compiler/scala/tools/nsc/models/Models.scala.xxx b/src/compiler/scala/tools/nsc/models/Models.scala
index e95976ed19..d1ae21ba53 100644
--- a/src/compiler/scala/tools/nsc/models/Models.scala.xxx
+++ b/src/compiler/scala/tools/nsc/models/Models.scala
@@ -7,17 +7,16 @@ package scala.tools.nsc.models;
import scala.tools.nsc.Global;
import scala.tools.nsc.ast.Trees;
+import scala.tools.nsc.util.Position;
import scala.tools.nsc.symtab.Flags;
import scala.tools.nsc.symtab.Names;
-[_trait_] abstract class Models {
- val global : Global;
-
+class Models(val global : Global) {
import global._;
abstract class Model {
}
- abstract class HasTree extends Model {
+ abstract class HasTree(val parent : Composite) extends Model {
var tree : Tree = _;
def update(tree0 : Tree): Boolean = {
tree = tree0;
@@ -25,7 +24,7 @@ import scala.tools.nsc.symtab.Names;
}
def replacedBy(tree0 : Tree) : Boolean = true;
}
- class ImportMod extends HasTree {
+ class ImportMod(parent0 : Composite) extends HasTree(parent0) {
def treex = tree.asInstanceOf[Import];
override def replacedBy(tree0 : Tree) : Boolean = if (super.replacedBy(tree0) && tree0.isInstanceOf[Import]) {
@@ -34,34 +33,41 @@ import scala.tools.nsc.symtab.Names;
} else false;
}
- abstract class Composite extends Model {
+ [_trait_] abstract class Composite extends Model {
import scala.collection.mutable._;
- class Members extends HashSet[HasTree] with ObservableSet[HasTree, Members] {
- override def +=(elem: HasTree): Unit = super.+=(elem);
- override def -=(elem: HasTree): Unit = super.-=(elem);
- override def clear: Unit = super.clear;
+ class Members extends HashSet[HasTree] /* with ObservableSet[HasTree, Members] */ {
+ // override def +=(elem: HasTree): Unit = super.+=(elem);
+ // override def -=(elem: HasTree): Unit = super.-=(elem);
+ // override def clear: Unit = super.clear;
}
object members extends Members;
- def isMember(tree : Tree) : Boolean = false;
+ def isMember(tree : Tree) : Boolean = tree.isInstanceOf[Import]; // imports welcome anywhere.
+
+ def member(tree: Tree, members : List[Tree]) : Tree = tree;
def update0(members1 : List[Tree]) : Boolean = {
+ // System.err.println("update0 " + this + " " + members1);
val marked = new HashSet[HasTree];
var updated = false;
- for (val mmbr1 <- members1) {
- var found = false;
- for (val mmbr <- members) if (!found && mmbr.replacedBy(mmbr1)) {
- found = true;
- updated = mmbr.update(mmbr1) || updated;
- marked += mmbr;
- }
- if (!found) {
- updated = true;
- val add = modelFor(mmbr1);
- add.update(mmbr1);
- members += (add);
- marked += add;
+ for (val mmbr1 <- members1) if (isMember(mmbr1)) {
+ val mmbr2 = member(mmbr1, members1);
+ if (mmbr2 != null) {
+ var found = false;
+ for (val mmbr <- members) if (!found && mmbr.replacedBy(mmbr2)) {
+ found = true;
+ updated = mmbr.update(mmbr2) || updated;
+ marked += mmbr;
+ }
+ if (!found) {
+ updated = true;
+ val add = modelFor(mmbr2, this);
+ add.update(mmbr2);
+ members += (add);
+ marked += add;
+ }
}
+ // System.err.println("update1 " + this + " " + members + " " + marked);
}
val sz = members.size;
members.intersect(marked);
@@ -70,42 +76,43 @@ import scala.tools.nsc.symtab.Names;
updated;
}
}
- abstract class MemberMod extends HasTree {
+ abstract class MemberMod(parent0 : Composite) extends HasTree(parent0) {
def treex = tree.asInstanceOf[MemberDef];
- def flags = new Flags.Flag(treex.mods0);
- def name : Name = { treex.name0; }
+
+ def name : Name = { treex.name; }
override def replacedBy(tree0 : Tree) : Boolean = if (super.replacedBy(tree0) && tree0.isInstanceOf[MemberDef]) {
val tree1 = tree0.asInstanceOf[MemberDef];
- treex.name0 == tree1.name0;
+ treex.name == tree1.name;
} else false;
override def update(tree0 : Tree): Boolean = {
- val updated = tree == null || (treex.mods0 != tree0.asInstanceOf[MemberDef].mods0);
+ val updated = tree == null || (treex.mods != tree0.asInstanceOf[MemberDef].mods);
super.update(tree0) || updated;
}
}
- abstract class MemberComposite extends MemberMod with Composite;
+ abstract class MemberComposite(parent0: Composite) extends MemberMod(parent0) with Composite;
- abstract class HasClassObjects extends Composite {
- override def isMember(tree : Tree) : Boolean = super.isMember(tree) || tree.isInstanceOf[ImplDef];
+ [_trait_] abstract class HasClassObjects extends Composite {
+ override def isMember(tree : Tree) : Boolean = (super.isMember(tree) ||
+ (tree.isInstanceOf[ImplDef]));
}
- abstract class ValOrDefMod extends MemberComposite with HasClassObjects {
+ abstract class ValOrDefMod(parent0: Composite) extends MemberComposite(parent0) with HasClassObjects {
def treey = tree.asInstanceOf[ValOrDefDef];
override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ValOrDefDef]);
override def update(tree0 : Tree): Boolean = {
val tree1 = tree0.asInstanceOf[ValOrDefDef];
val updated = tree == null || treex.tpe != tree1.tpe;
- update0(flatten(tree1.rhs0, (tree2 : Tree) => isMember(tree2)));
+ update0(flatten(tree1.rhs, (tree2 : Tree) => isMember(tree2)));
super.update(tree0) || updated;
}
}
- class ValMod extends ValOrDefMod {
+ class ValMod(parent0: Composite) extends ValOrDefMod(parent0) {
def treez = tree.asInstanceOf[ValDef];
override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ValDef]);
}
- class DefMod extends ValOrDefMod {
+ class DefMod(parent0: Composite) extends ValOrDefMod(parent0) {
def treez = tree.asInstanceOf[DefDef];
override def replacedBy(tree0 : Tree) : Boolean = if (super.replacedBy(tree0) && tree0.isInstanceOf[DefDef]) {
@@ -114,54 +121,71 @@ import scala.tools.nsc.symtab.Names;
val tpz = for (val vd <- treez.vparamss) yield for (val xd <- vd) yield xd.tpe;
val tp1 = for (val vd <- tree1.vparamss) yield for (val xd <- vd) yield xd.tpe;
tpz == tp1;
- } else false;
+ } else false;
} else false;
}
- abstract class ImplMod extends MemberComposite with HasClassObjects {
+ abstract class ImplMod(parent0: Composite) extends MemberComposite(parent0) with HasClassObjects {
def treey = tree.asInstanceOf[ImplDef];
override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ImplDef]);
- override def isMember(tree : Tree) : Boolean = super.isMember(tree) || tree.isInstanceOf[ValOrDefDef] || tree.isInstanceOf[AliasTypeDef];
+ override def isMember(tree : Tree) : Boolean = (super.isMember(tree) ||
+ (tree.isInstanceOf[ValOrDefDef]
+ /* && !tree.asInstanceOf[ValOrDefDef].mods.isPrivate */
+ /* && !tree.asInstanceOf[ValOrDefDef].mods.isAccessor */) ||
+ tree.isInstanceOf[AliasTypeDef]);
+
+ override def member(tree : Tree, members : List[Tree]) : Tree = {
+ val tree0 = if (tree.isInstanceOf[DefDef]) {
+ val ddef = tree.asInstanceOf[DefDef];
+ if (ddef.mods.isAccessor && ddef.symbol != null) {
+ val sym = ddef.symbol.accessed;
+ val ret = for (val member <- members; member.symbol == sym) yield member;
+ if (ret.isEmpty) tree;
+ else ret.head;
+ } else tree;
+ } else super.member(tree, members);
+ val sym = tree0.symbol;
+ if (sym.pos == Position.NOPOS) null;
+ else tree0;
+ }
- override def update(tree0 : Tree): Boolean = {
- val tree1 = tree0.asInstanceOf[ImplDef];
-
- var updated = update0(tree1.impl0.body);
- // XXX: ignore parents for now!
+ def children(tree0 : Tree) : List[Tree] = tree0.asInstanceOf[ImplDef].impl.body;
- (super.update(tree0) || updated) && !flags.isPrivate;
+ override def update(tree0 : Tree): Boolean = {
+ var updated = update0(children(tree0));
+ (super.update(tree0) || updated);
}
-
-
}
- class ClassMod extends ImplMod {
+ class ClassMod(parent0: Composite) extends ImplMod(parent0) {
def treez = tree.asInstanceOf[ClassDef];
override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ClassDef]);
-
- override def update(tree0 : Tree): Boolean = {
- // XXX: type parameters and this type!
-
-
- super.update(tree0);
- }
}
- class ObjectMod extends ImplMod {
+ class ObjectMod(parent0: Composite) extends ImplMod(parent0) {
def treez = tree.asInstanceOf[ModuleDef];
override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ModuleDef]);
}
- class AliasTypeMod extends MemberMod {
+ class AliasTypeMod(parent0: Composite) extends MemberMod(parent0) {
def treey = tree.asInstanceOf[AliasTypeDef];
override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[AliasTypeDef]);
}
- class SourceMod(val unit : CompilationUnit) extends Composite with HasClassObjects {
- override def isMember(tree : Tree) : Boolean = super.isMember(tree) || tree.isInstanceOf[Import];
+ class AbsTypeMod(parent0: Composite) extends HasTree(parent0) {
+ def treey = tree.asInstanceOf[AbsTypeDef];
+ override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[AbsTypeDef]);
}
+ class SourceMod(val original : CompilationUnit) extends Composite with HasClassObjects {
+ // update(unit);
+ def update(unit : CompilationUnit) = unit.body match {
+ case pdef : PackageDef => update0(pdef.stats);
+ case _ =>
+ }
+ override def isMember(tree : Tree) : Boolean = super.isMember(tree) || tree.isInstanceOf[Import];
+ }
- def flatten0(exprs : List[Tree], filter: (Tree) => Boolean) : List[Tree] =
+ def flatten0(exprs : List[Tree], filter: (Tree) => Boolean) : List[Tree] =
for (val expr <- exprs; val t : Tree <- flatten(expr,filter)) yield t;
- def flatten(expr : Tree, filter: (Tree) => Boolean) : List[Tree] =
+ def flatten(expr : Tree, filter: (Tree) => Boolean) : List[Tree] =
if (filter(expr)) expr :: Nil; else expr match {
case Block(stats,last) => flatten0(stats, filter) ::: flatten(last, filter);
case If(cond,thenp,elsep) => flatten(cond,filter) ::: flatten(thenp,filter) ::: flatten(elsep,filter);
@@ -171,19 +195,20 @@ import scala.tools.nsc.symtab.Names;
case Throw(expr0) => flatten(expr0,filter);
case Try(block,catches,finalizer) => flatten(block,filter) ::: flatten(finalizer,filter) ::: flatten0(catches, filter);
case Match(selector,cases) => flatten(selector,filter) ::: flatten0(cases, filter);
- case Apply(fun,args) => flatten(fun,filter) ::: flatten0(args,filter);
- case TypeApply(fun,args) => flatten(fun,filter) ::: flatten0(args,filter);
+ case Apply(fun,args) => flatten(fun,filter) ::: flatten0(args,filter);
+ case TypeApply(fun,args) => flatten(fun,filter) ::: flatten0(args,filter);
case _ => Nil;
}
- def modelFor(tree: Tree): HasTree = tree match {
- case _: ValDef => new ValMod();
- case _: DefDef => new DefMod();
- case _: ClassDef => new ClassMod();
- case _: ModuleDef => new ObjectMod();
- case _: AliasTypeDef => new AliasTypeMod();
- case _: Import => new ImportMod();
+ def modelFor(tree: Tree, parent: Composite): HasTree = tree match {
+ case _: ValDef => new ValMod(parent);
+ case _: DefDef => new DefMod(parent);
+ case _: ClassDef => new ClassMod(parent);
+ case _: ModuleDef => new ObjectMod(parent);
+ case _: AliasTypeDef => new AliasTypeMod(parent);
+ case _: AbsTypeDef => new AbsTypeMod(parent);
+ case _: Import => new ImportMod(parent);
}
}
diff --git a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala
index 51d127b54b..a30b752e15 100644
--- a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala
+++ b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala
@@ -88,6 +88,7 @@ class SemanticTokens(val compiler: Compiler) {
// already gap
override def convertToGap : Pair[Int,Actual] = new Pair(0, this);
}
+ def Process(unit : CompilationUnit) = new Process(unit);
class Process(val unit : CompilationUnit) {
def source = unit.source;
@@ -147,8 +148,6 @@ class SemanticTokens(val compiler: Compiler) {
case _ =>
}
if (tree0.pos != Position.NOPOS) tree0 match {
-
-
case tree : ImplDef =>
val pos = tree.namePos(unit.source);
if (pos == Position.NOPOS) {
@@ -315,15 +314,16 @@ class SemanticTokens(val compiler: Compiler) {
def buildUse(term : Symbol, pos : Int) = buildSym(term, pos, false);
def buildDef(term : Symbol, pos : Int) = buildSym(term, pos, true);
- def buildSym(term : Symbol, pos : Int, isDef : Boolean) : Unit = if (term.hasFlag(Flags.ACCESSOR)) buildSym(term.accessed, pos, isDef)
- else if (pos == Position.NOPOS) {
- System.err.println("NOPOS: " + term);
- Thread.dumpStack();
- } else if (term != NoSymbol) {
- val name = NameTransformer.decode(term.name.toString()).toString().trim();
- val buf = unit.source.content;
- val cs = name.toChars;
- var idx = 0;
+ def buildSym(term : Symbol, pos : Int, isDef : Boolean) : Unit =
+ if (term.hasFlag(Flags.ACCESSOR)) buildSym(term.accessed, pos, isDef);
+ else if (pos == Position.NOPOS) {
+ System.err.println("NOPOS: " + term);
+ Thread.dumpStack();
+ } else if (term != NoSymbol) {
+ val name = NameTransformer.decode(term.name.toString()).toString().trim();
+ val buf = unit.source.content;
+ val cs = name.toChars;
+ var idx = 0;
if (cs.length + pos > buf.length) {
return;
}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index a07da4ad57..64684c80ad 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -6,7 +6,9 @@
package scala.tools.nsc.symtab;
import java.io.IOException;
+import java.io.File;
import scala.tools.nsc.util.Position;
+import scala.tools.nsc.util.ClassPath;
import scala.tools.util.{AbstractFile};
import scala.tools.nsc.util.NameTransformer;
import scala.collection.mutable.HashMap;
@@ -25,17 +27,18 @@ abstract class SymbolLoaders {
* name of file loaded for completion as a result.
* Can throw an IOException on error.
*/
- abstract class SymbolLoader(file: AbstractFile) extends LazyType {
+ abstract class SymbolLoader extends LazyType {
/** Load source or class file for `root', return */
protected def doComplete(root: Symbol): unit;
/** The kind of file that's processed by this loader */
protected def kindString: String;
private var ok = false;
-
- private def setSource(sym: Symbol): unit = sym match {
- case clazz: ClassSymbol => clazz.sourceFile = file;
- case _ =>
+ private def setSource(sym: Symbol, sourceFile0: AbstractFile): unit = sym match {
+ case clazz: ClassSymbol => if (sourceFile0 != null) clazz.sourceFile = sourceFile0;
+ case _ => if (sourceFile0 != null) if (false) System.err.println("YYY: " + sym + " " + sourceFile0);
}
+ def sourceFile : AbstractFile = null;
+ protected def sourceString : String;
override def complete(root: Symbol): unit = {
try {
@@ -43,12 +46,16 @@ abstract class SymbolLoaders {
val currentphase = phase;
doComplete(root);
phase = currentphase;
- def source = kindString + " " + file;
+ def source = kindString + " " + sourceString;
informTime("loaded " + source, start);
if (root.rawInfo != this) {
ok = true;
- setSource(root.linkedModule.moduleClass);
- setSource(root.linkedClass);
+ val sourceFile0 = if (sourceFile == null) (root match {
+ case clazz: ClassSymbol => clazz.sourceFile;
+ case _ => null;
+ }) else sourceFile;
+ setSource(root.linkedModule, sourceFile0);
+ setSource(root.linkedClass, sourceFile0);
} else error(source + " does not define " + root)
} catch {
case ex: IOException =>
@@ -75,7 +82,11 @@ abstract class SymbolLoaders {
/** Load contents of a package
*/
- class PackageLoader(directory: AbstractFile) extends SymbolLoader(directory) {
+ class PackageLoader(directory: ClassPath.Context) extends SymbolLoader {
+ // System.err.println("PACKAGE LOADER: " + directory);
+
+ protected def sourceString = directory.toString();
+
protected def doComplete(root: Symbol): unit = {
assert(root.isPackageClass, root);
root.setInfo(new PackageClassInfoType(new Scope(), root));
@@ -91,11 +102,12 @@ abstract class SymbolLoaders {
root.info.decls.enter(pkg)
}
- def enterClassAndModule(str: String, completer: SymbolLoader, sfile : AbstractFile): unit = {
+ def enterClassAndModule(str: String, completer: SymbolLoader): unit = {
val owner = if (root.isRoot) definitions.EmptyPackageClass else root;
val name = newTermName(str);
val clazz = owner.newClass(Position.NOPOS, name.toTypeName);
val module = owner.newModule(Position.NOPOS, name);
+ if (completer.sourceFile != null) clazz.sourceFile = completer.sourceFile;
clazz.setInfo(completer);
module.setInfo(completer);
module.moduleClass.setInfo(moduleClassLoader);
@@ -104,75 +116,63 @@ abstract class SymbolLoaders {
assert(clazz.linkedModule == module, module);
assert(module.linkedClass == clazz, clazz);
}
-
- val sources = new HashMap[String, AbstractFile];
- val classes = new HashMap[String, AbstractFile];
- val packages = new HashMap[String, AbstractFile];
- val it = directory.list();
- while (it.hasNext()) {
- val file = it.next().asInstanceOf[AbstractFile];
- val filename = file.getName();
- if (file.isDirectory()) {
- if (filename != "META_INF" && !packages.isDefinedAt(filename)) packages(filename) = file;
-/*
- } else if (filename.endsWith(".symbl")) {
- val name = filename.substring(0, filename.length() - 6);
- if (isValid(name) &&
- (!classes.isDefinedAt(name) || classes(name).getName().endsWith(".class")))
- classes(name) = file;
-*/
- } else if (filename.endsWith(".class")) {
- val name = filename.substring(0, filename.length() - 6);
- if (isValid(name) && !classes.isDefinedAt(name))
- classes(name) = file;
- } else if (filename.endsWith(".scala")) {
- val name = filename.substring(0, filename.length() - 6);
- if (isValid(name) && !sources.isDefinedAt(name))
- sources(name) = file;
- }
- }
- for (val Pair(name, sfile) <- sources.elements) {
- classes.get(name) match {
- case Some(cfile) if (cfile.lastModified() >= sfile.lastModified()) => {}
- case _ => enterClassAndModule(name, new SourcefileLoader(sfile), sfile);
- }
+ val classes = new HashMap[String, ClassPath.Context];
+ val packages = new HashMap[String, ClassPath.Context];
+ for (val dir <- directory.classes) if (dir != null) {
+ val it = dir.list();
+ while (it.hasNext()) {
+ val file = it.next().asInstanceOf[AbstractFile];
+ if (file.isDirectory() && directory.validPackage(file.getName()) && !packages.isDefinedAt(file.getName()))
+ packages(file.getName()) = directory.find(file.getName(), true);
+ else if (!file.isDirectory() && file.getName().endsWith(".class")) {
+ val name = file.getName().substring(0, file.getName().length() - (".class").length());
+ if (isValid(name) && !classes.isDefinedAt(name))
+ classes(name) = directory.find(name, false);
+ }
+ }
}
- for (val Pair(name, cfile) <- classes.elements) {
- val sfile = sources.get(name) match {
- case Some(sfile0) => sfile0;
- case _ => null;
+ for (val dir <- directory.sources) if (dir != null) {
+ val it = dir.location.list();
+ while (it.hasNext()) {
+ val file = it.next().asInstanceOf[AbstractFile];
+ if (file.isDirectory() && directory.validPackage(file.getName()) && !packages.isDefinedAt(file.getName()))
+ packages(file.getName()) = directory.find(file.getName(), true);
+ else if (dir.compile && !file.isDirectory() && file.getName().endsWith(".scala")) {
+ val name = file.getName().substring(0, file.getName().length() - (".scala").length());
+ if (isValid(name) && !classes.isDefinedAt(name))
+ classes(name) = directory.find(name, false);
+ }
}
- sources.get(name) match {
- case Some(sfile) if (sfile.lastModified() > cfile.lastModified()) => {}
- case _ =>
- val loader =
-/* if (cfile.getName().endsWith(".symbl")) new SymblfileLoader(cfile)
- else */
- new ClassfileLoader(cfile);
- enterClassAndModule(name, loader, sfile)
- }
}
- for (val Pair(name, file) <- packages.elements) {
- if (!sources.contains(name) && !classes.contains(name))
- enterPackage(name, new PackageLoader(file));
+ //if (!packages.isEmpty) System.err.println("COMPLETE: " + packages);
+ //if (! classes.isEmpty) System.err.println("COMPLETE: " + classes);
+ // do classes first
+
+ for (val Pair(name, file) <- classes.elements) {
+ val loader = if (!file.isSourceFile) new ClassfileLoader(file.file, file.sourceFile, file.sourcePath);
+ else new SourcefileLoader(file.file);
+ enterClassAndModule(name, loader);
}
+ for (val Pair(name, file) <- packages.elements) enterPackage(name, new PackageLoader(file));
}
protected def kindString: String = "directory path"
}
- private object classfileParser extends ClassfileParser {
- val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global;
- }
-
/*
private object symblfileParser extends SymblfileParser {
val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global;
}
*/
- class ClassfileLoader(file: AbstractFile) extends SymbolLoader(file) {
- protected def doComplete(root: Symbol): unit = classfileParser.parse(file, root);
+ class ClassfileLoader(classFile: AbstractFile, sourceFile0: AbstractFile, sourcePath0: AbstractFile) extends SymbolLoader {
+ private object classfileParser extends ClassfileParser {
+ val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global;
+ override def sourcePath = sourcePath0; /* could be null */
+ }
+ protected def doComplete(root: Symbol): unit = classfileParser.parse(classFile, root);
protected def kindString: String = "class file";
+ protected def sourceString = classFile.toString();
+ override def sourceFile : AbstractFile = sourceFile0;
}
/*
class SymblfileLoader(file: AbstractFile) extends SymbolLoader(file) {
@@ -180,14 +180,17 @@ abstract class SymbolLoaders {
protected def kindString: String = "symbl file";
}
*/
- class SourcefileLoader(file: AbstractFile) extends SymbolLoader(file) {
- protected def doComplete(root: Symbol): unit = global.currentRun.compileLate(file);
+ class SourcefileLoader(sourceFile0: AbstractFile) extends SymbolLoader {
+ protected def doComplete(root: Symbol): unit = global.currentRun.compileLate(sourceFile0);
protected def kindString: String = "source file";
+ override def sourceFile = sourceFile0;
+ protected def sourceString = sourceFile0.toString();
}
- object moduleClassLoader extends SymbolLoader(null) {
+ object moduleClassLoader extends SymbolLoader {
protected def doComplete(root: Symbol): unit =
root.sourceModule.initialize;
protected def kindString: String = "";
+ protected def sourceString = "";
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index ffd5add6f0..effe6a408c 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -21,6 +21,7 @@ import scala.tools.util.AbstractFileReader;
import java.io.IOException;
abstract class ClassfileParser {
+ def sourcePath : AbstractFile = null;
val global: Global;
import global._;
@@ -346,6 +347,14 @@ abstract class ClassfileParser {
val meta = pool.getName(in.nextChar()).toString().trim();
metaParser.parse(meta, sym, symtype);
this.hasMeta = true;
+ case nme.SourceFileATTR =>
+ assert(attrLen == 2);
+ val source = pool.getName(in.nextChar());
+ if (sourcePath != null) sym match {
+ case clazz: ClassSymbol =>
+ clazz.sourceFile = sourcePath.lookupPath(source.toString(), false);
+ // System.err.println("clazz=" + clazz + " @ " + clazz.sourceFile);
+ }
case _ =>
in.skip(attrLen)
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala
index ea88451ef6..7709a5ba5d 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala
@@ -45,6 +45,7 @@ object PickleFormat {
* | 34 LITERALnull len_Nat
* | 35 LITERALzero len_Nat
* | 36 ATTRIBUTE sym_Ref type_Ref {constant_Ref} <not yet>
+ * | 37 POS len_Nat sym_Ref value_Long
* SymbolInfo = name_Ref owner_Ref flags_Nat [privateWithin_Ref] info_Ref
* NameInfo = <character sequence of length len_Nat in Utf8 format>
* NumInfo = <len_Nat-byte signed number in big endian format>
@@ -90,6 +91,7 @@ object PickleFormat {
final val LITERALstring = 33;
final val LITERALnull = 34;
final val LITERALzero = 35;
+ final val POS = 37;
final val ATTRIBUTE = 40;
final val firstSymTag = NONEsym;
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 639cb71bf0..e8441dde87 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -8,9 +8,12 @@ package scala.tools.nsc.symtab.classfile;
import java.io._;
import java.lang.{Float, Double}
import scala.collection.mutable.HashMap;
+import scala.tools.nsc.util.Position;
import Flags._;
import PickleFormat._;
+
+
/**
* Serialize a top-level module and/or class;
* @see EntryTags.scala for symbol table attribute format.
@@ -77,17 +80,21 @@ abstract class Pickler extends SubComponent {
ep = ep + 1;
true
}
+ case class PositionSymbol(val sym : Symbol, val pos : Int);
/** Store symbol in index. If symbol is local, also store everything it refers to. */
def putSymbol(sym: Symbol): unit = if (putEntry(sym)) {
if (isLocal(sym)) {
putEntry(sym.name);
+ if (sym.pos != Position.NOPOS) putEntry(new PositionSymbol(sym, sym.pos));
+
putSymbol(sym.owner);
putSymbol(sym.privateWithin);
putType(sym.info);
if (sym.thisSym != sym)
putType(sym.typeOfThis);
putSymbol(sym.alias);
+
//for (val attr <- sym.attributes) putAttribute(sym, attr);
} else if (sym != NoSymbol) {
putEntry(if (sym.isModuleClass) sym.name.toTermName else sym.name);
@@ -223,6 +230,7 @@ abstract class Pickler extends SubComponent {
for (val c <- cs) writeRef(cs);
ATTRIBUTE
*/
+ case PositionSymbol(sym, pos) => writeRef(sym); writeLong(pos); POS;
case _ =>
throw new FatalError("bad entry: " + entry + " " + entry.getClass());//debug
}
@@ -239,7 +247,7 @@ abstract class Pickler extends SubComponent {
writeNat(MinorVersion);
writeNat(ep);
if (settings.debug.value) log("" + ep + " entries");//debug
- for (val i <- Iterator.range(0, ep)) writeEntry(entries(i))
+ for (val i <- Iterator.range(0, ep)) writeEntry(entries(i));
}
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
index 3ddf7fb08f..5f268b9281 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
@@ -8,6 +8,7 @@ package scala.tools.nsc.symtab.classfile;
import scala.tools.nsc.util.Position;
import scala.tools.util.UTF8Codec;
import java.lang.{Float, Double};
+
import Flags._;
import PickleFormat._;
import collection.mutable.HashMap;
@@ -32,8 +33,10 @@ abstract class UnPickler {
private val entries = new Array[AnyRef](index.length);
private val symScopes = new HashMap[Symbol, Scope];
- for (val i <- Iterator.range(0, index.length))
+ for (val i <- Iterator.range(0, index.length)) {
if (isSymbolEntry(i)) { at(i, readSymbol); () }
+ else if (isPosition(i)) { at(i, readPosition); () }
+ }
if (settings.debug.value) global.log("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug
@@ -60,12 +63,13 @@ abstract class UnPickler {
(tag != CLASSsym || !isRefinementSymbolEntry(i)))
}
+ private def isPosition(i: int): boolean = bytes(index(i)) == POS;
+
/** Does entry represent an (internal or external) symbol */
private def isSymbolRef(i: int): boolean = {
val tag = bytes(index(i));
(firstSymTag <= tag && tag <= lastExtSymTag)
}
-
/** Does entry represent a refinement symbol?
* pre: Entry is a class symbol
*/
@@ -105,6 +109,16 @@ abstract class UnPickler {
}
}
+ private def readPosition(): Integer = {
+ val tag = readByte();
+ val len = readNat();
+ val start = readIndex;
+ val sym = readSymbolRef();
+ val pos = readLong(len - (readIndex - start)).asInstanceOf[Int];
+ assert(sym.pos == Position.NOPOS);
+ sym.setPos(pos);
+ new Integer(pos);
+ }
/** Read a symbol */
private def readSymbol(): Symbol = {
val tag = readByte();
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 0c8937f1f9..ec9677f7be 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -84,8 +84,16 @@ trait Namers requires Analyzer {
def enterInScope(sym: Symbol): Symbol = {
if (!(sym.isSourceMethod && sym.owner.isClass)) {
val prev = context.scope.lookupEntry(sym.name);
- if (prev != null && prev.owner == context.scope && !prev.sym.isSourceMethod)
- doubleDefError(sym.pos, prev.sym);
+ if (prev != null && prev.owner == context.scope && !prev.sym.isSourceMethod) {
+ if (sym.sourceFile == null && prev.sym.sourceFile == null) {}
+ else if (sym.sourceFile != null && prev.sym.sourceFile != null &&
+ sym.sourceFile.equals(prev.sym.sourceFile)) {}
+ else {
+ System.err.println("SYM: " + sym.sourceFile);
+ System.err.println("PRV: " + prev.sym.sourceFile);
+ doubleDefError(sym.pos, prev.sym);
+ }
+ }
}
context.scope enter sym;
sym
@@ -118,8 +126,20 @@ trait Namers requires Analyzer {
c = enterInScope(context.owner.newClass(pos, name)).setFlag(flags | inConstructorFlag);
}
if (c.owner.isPackageClass) {
- currentRun.symSource(c) = context.unit.source.getFile();
- c.sourceFile = context.unit.source.getFile();
+ val file = context.unit.source.getFile();
+ val clazz = c.asInstanceOf[ClassSymbol];
+ if (file != null) {
+ if (clazz.sourceFile != null && !clazz.sourceFile.equals(file)) // double def.
+ throw new Error(""+clazz.sourceFile + " vs. " + file + " SYM=" + c);
+ else clazz.sourceFile = file;
+
+ }
+ if (clazz.sourceFile != null) {
+ if (currentRun.symSource.isDefinedAt(c) && currentRun.symSource(c) != null &&
+ !currentRun.symSource(c).equals(clazz.sourceFile))
+ throw new Error(""+currentRun.symSource(c) + " vs. " + clazz.sourceFile + " SYM=" + currentRun + " " + c);
+ else currentRun.symSource(c) = clazz.sourceFile;
+ }
}
c
}
diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala
new file mode 100644
index 0000000000..a60f914ac6
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala
@@ -0,0 +1,211 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2004, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.tools.nsc.util;
+
+import scala.tools.util.AbstractFile;
+import scala.collection.mutable.ArrayBuffer;
+import java.io.FileNotFoundException;
+import java.io.File;
+import java.util.StringTokenizer;
+
+/** Richer classpath abstraction than files.
+ * Roughly based on Eclipse's classpath abstractions.
+ *
+ * @author Sean McDirmid
+ */
+object ClassPath {
+
+ class Source(val location : AbstractFile, val compile : Boolean);
+
+ abstract class Entry {
+ def location : AbstractFile;
+ def source : Source;
+ }
+
+ class Output(val location : AbstractFile, val sourceFile : AbstractFile) extends Entry {
+ def source = new Source(sourceFile, true);
+ }
+ class Library(val location : AbstractFile) extends Entry {
+ def doc : AbstractFile = null;
+ def sourceFile : AbstractFile = null;
+ def source = if (sourceFile == null) null else new Source(sourceFile, false);
+ }
+
+ class Context(val classes : List[AbstractFile], val sources : List[Source]) {
+ def find(name : String, isDir : boolean) = {
+ assert(isPackage);
+ def find0(classes : List[AbstractFile], sources : List[Source]) : Context = {
+ assert(classes.length == sources.length);
+ if (classes.isEmpty) new Context(Nil, Nil);
+ else {
+ val ret = find0(classes.tail, sources.tail);
+
+ val clazz = if (classes.head == null) null; else
+ classes.head.lookupPath(name + (if (!isDir) ".class" else ""), isDir);
+
+ val source = {
+ if (sources.head == null) null;
+ else {
+ val source0 = sources.head.location.lookupPath(name + (if (!isDir) ".scala" else ""), isDir);
+ if (source0 != null) source0;
+ else if (clazz != null && !isDir) sources.head.location; // directory where we can find source.
+ else null;
+ }
+ }
+ if (clazz == null && source == null) ret;
+ else new Context(clazz :: ret.classes,
+ (if (source != null) new Source(source, sources.head.compile) else null)
+ :: ret.sources);
+ }
+ }
+ find0(classes, sources);
+ }
+
+ def isPackage = {
+ if (classes.head != null) classes.head.isDirectory();
+ else sources.head.location.isDirectory();
+ }
+ def name = {
+ val name = if (classes.head != null) classes.head.getName() else sources.head.location.getName();
+ if (isPackage) name;
+ else name.substring(0, name.length() - (".class").length());
+ }
+
+ override def toString() : String = toString(classes, sources);
+
+ def toString(classes0 : List[AbstractFile], sources0 : List[Source]) : String =
+ if (classes0.isEmpty) "";
+ else
+ ((if (classes0.head == null) "<none>" else classes0.head.toString()) + (if (sources0.head != null) {
+ "::" + sources0.head.location.toString();
+ } else "")) + ":" + toString(classes0.tail, sources0.tail);
+
+ def file = {
+ assert(!isPackage);
+ if (classes.isEmpty) null;
+ else if (sources.head == null || sources.head.location.isDirectory() || !sources.head.compile) {
+ assert(classes.head != null);
+ classes.head;
+ } else if (classes.head == null) {
+ sources.head.location;
+ } else if (sources.head.location.lastModified() >= classes.head.lastModified()) sources.head.location;
+ else classes.head;
+ }
+ def isSourceFile = file.getName().endsWith(".scala");
+
+ def sourceFile =
+ if (sources.isEmpty || sources.head == null) null;
+ else if (sources.head.location.isDirectory()) null;
+ else sources.head.location;
+
+ def sourcePath =
+ if (sources.isEmpty || sources.head == null) null;
+ else if (!sources.head.location.isDirectory()) null;
+ else sources.head.location;
+
+ def validPackage(name : String) : Boolean =
+ if (name.equals("META-INF")) false;
+ else if (name.startsWith(".")) false;
+ else true;
+
+ def complete : List[Context] = {
+ assert(isPackage);
+ def complete0(classes : List[AbstractFile], sources : List[Source]) : List[Context] =
+ if (classes.isEmpty) Nil;
+ else if (classes.head == null && sources.head == null) complete0(classes.tail, sources.tail);
+ else {
+ var ret : List[Context] = Nil;
+ if (classes.head != null) {
+ val i = classes.head.list();
+ while (i.hasNext()) {
+ val file = i.next().asInstanceOf[AbstractFile];
+ if (!file.isDirectory() && file.getName().endsWith(".class")) {
+ val name = file.getName().substring(0, file.getName().length() - (".class").length());
+ ret = find(name, false) :: ret;
+ } else if (file.isDirectory() && validPackage(file.getName())) {
+ ret = (find(file.getName(), true) :: ret);
+ // System.err.println("FILE: " + file.getName() + " RET=" + ret.head);
+ }
+ }
+ }
+ if (sources.head != null && sources.head.compile) {
+ val j = sources.head.location.list();
+ while (j.hasNext()) {
+ val file = j.next().asInstanceOf[AbstractFile];
+ if (!file.isDirectory() && file.getName().endsWith(".scala")) {
+ val name = file.getName().substring(0, file.getName().length() - (".scala").length());
+ if (classes.head == null ||
+ classes.head.lookupPath(name + ".class", false) == null) ret = find(name, false) :: ret;
+ } else if (file.isDirectory() && validPackage(file.getName())) {
+ if (classes.head == null || classes.head.lookupPath(file.getName(), true) == null)
+ ret = find(file.getName(), true) :: ret;
+ }
+ }
+ }
+ ret ::: complete0(classes.tail, sources.tail);
+ }
+ complete0(classes, sources);
+ }
+ }
+
+ class Build(val output : Output) {
+ val entries = new ArrayBuffer[Entry];
+
+ def root = {
+ val classes = for (val entry <- entries.toList) yield entry.location;
+ val sources = for (val entry <- entries.toList) yield entry.source;
+ new Context(classes, sources);
+ }
+
+
+ def this(classpath : String, source : String, output : String, boot : String, extdirs : String) = {
+ this(new Output(AbstractFile.getDirectory(output), AbstractFile.getDirectory(source)));
+
+ if (this.output.location == null) throw new FileNotFoundException("output location \"" + output + "\" not found");
+ if (this.output.source == null) throw new FileNotFoundException("source location \"" + source + "\" not found");
+
+ addFilesInPath(boot);
+ addArchivesInExtDirPath(extdirs);
+ entries += this.output;
+ addFilesInPath(classpath);
+ }
+ def library(classes : String, sources : String) = {
+ assert(classes != null);
+ val location = AbstractFile.getDirectory(classes);
+ val sourceFile0 = (if (sources != null) AbstractFile.getDirectory(sources) else null);
+ class Library0 extends Library(location) {
+ override def sourceFile = sourceFile0;
+ }
+ entries += new Library0();
+ }
+
+ private def addFilesInPath(path : String) = {
+ val strtok = new StringTokenizer(path, File.pathSeparator);
+ while (strtok.hasMoreTokens()) {
+ val file = AbstractFile.getDirectory(strtok.nextToken());
+ if (file != null) entries += (new Library(file));
+ }
+ }
+ private def addArchivesInExtDirPath(path : String) = {
+ val strtok = new StringTokenizer(path, File.pathSeparator);
+ while (strtok.hasMoreTokens()) {
+ val file = AbstractFile.getDirectory(strtok.nextToken());
+ val files = (if (file != null) file.list() else null);
+ if (files != null) while(files.hasNext()) {
+ val file0 = files.next().asInstanceOf[AbstractFile];
+ val name = file0.getName();
+ if (name.endsWith(".jar") || name.endsWith(".zip")) {
+ val archive = AbstractFile.getDirectory(new File(file.getFile(), name));
+ if (archive != null) entries += (new Library(archive));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala
index bf502cac3b..29f4d74cf7 100644
--- a/src/compiler/scala/tools/nsc/util/Position.scala
+++ b/src/compiler/scala/tools/nsc/util/Position.scala
@@ -68,12 +68,14 @@ class Position( val source : SourceFile, val offset: Int) {
/** Returns a string representation of the encoded position. */
override def toString(): String = {
val sb = new StringBuffer();
- sb.append(source.file.getPath());
- if (hasOffset) {
- sb.append(line);
- sb.append(':');
- sb.append(column);
- }
+ if (source != null) {
+ sb.append(source.file.getPath());
+ if (hasOffset) {
+ sb.append(line);
+ sb.append(':');
+ sb.append(column);
+ }
+ } else sb.append("::" + offset);
sb.toString();
}
}
diff --git a/src/compiler/scala/tools/util/ZipArchive.java b/src/compiler/scala/tools/util/ZipArchive.java
index 6367b28013..b3cd9e6538 100644
--- a/src/compiler/scala/tools/util/ZipArchive.java
+++ b/src/compiler/scala/tools/util/ZipArchive.java
@@ -196,7 +196,7 @@ public final class ZipArchive extends PlainFile {
// Private Class - FileEntry
/** A regular file archive entry */
- private final class FileEntry extends Entry {
+ public final class FileEntry extends Entry {
public final ZipEntry entry;