summaryrefslogtreecommitdiff
path: root/sources/scala/tools/nsc/typechecker/Contexts.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2005-04-28 17:37:27 +0000
committerMartin Odersky <odersky@gmail.com>2005-04-28 17:37:27 +0000
commit0baff379fd40abb757551c7a02676b051b1c8e17 (patch)
tree7352cfd392c87bd78781a66a74df0e00346c829e /sources/scala/tools/nsc/typechecker/Contexts.scala
parent6d81466523463b6a7795e841a7cfdf7ad3e06356 (diff)
downloadscala-0baff379fd40abb757551c7a02676b051b1c8e17.tar.gz
scala-0baff379fd40abb757551c7a02676b051b1c8e17.tar.bz2
scala-0baff379fd40abb757551c7a02676b051b1c8e17.zip
*** empty log message ***
Diffstat (limited to 'sources/scala/tools/nsc/typechecker/Contexts.scala')
-rwxr-xr-xsources/scala/tools/nsc/typechecker/Contexts.scala165
1 files changed, 128 insertions, 37 deletions
diff --git a/sources/scala/tools/nsc/typechecker/Contexts.scala b/sources/scala/tools/nsc/typechecker/Contexts.scala
index afaa1542b3..19d02e6856 100755
--- a/sources/scala/tools/nsc/typechecker/Contexts.scala
+++ b/sources/scala/tools/nsc/typechecker/Contexts.scala
@@ -5,14 +5,16 @@
// $Id$
package scala.tools.nsc.typechecker;
+import symtab.Flags._;
import scala.tools.util.Position;
class Contexts: Analyzer {
import global._;
val NoContext = new Context {
- override def imports: List[ImportInfo] = List();
+ override def implicitss: List[List[ImplicitInfo]] = List();
}
+ NoContext.enclClass = NoContext;
val startContext = {
import definitions._;
@@ -22,11 +24,11 @@ class Contexts: Analyzer {
definitions.RootClass.info.decls);
def addImport(pkg: Symbol): unit = {
val qual = gen.mkStableRef(pkg);
- val impTree = Import(qual, List(Pair(nme.WILDCARD, null)))
- setSymbol NoSymbol.newImport(Position.NOPOS).setInfo(ImportType(qual))
- setType NoType;
- sc = sc.make(
- Template(List(), List(impTree)) setSymbol NoSymbol setType NoType, sc.owner, sc.scope)
+ sc = sc.makeNewImport(
+ Import(qual, List(Pair(nme.WILDCARD, null)))
+ setSymbol NoSymbol.newImport(Position.NOPOS).setInfo(ImportType(qual))
+ setType NoType);
+ sc.depth = sc.depth + 1
}
if (!settings.noimports.value) {
addImport(JavaLangPackage);
@@ -40,7 +42,7 @@ class Contexts: Analyzer {
class Context {
var unit: CompilationUnit = _;
var tree: Tree = _; // Tree associated with this context
- var owner: Symbol = _; // The current owner
+ var owner: Symbol = NoSymbol; // The current owner
var scope: Scope = _; // The current scope
var outer: Context = _; // The next outer context
var enclClass: Context = _; // The next outer context whose tree is a
@@ -48,15 +50,19 @@ class Contexts: Analyzer {
var variance: int = _; // Variance relative to enclosing class.
private var _undetparams: List[Symbol] = List(); // Undetermined type parameters
var depth: int = 0;
+ var imports: List[ImportInfo] = List();
+
+ var reportAmbiguousErrors = false;
+ var reportGeneralErrors = false;
def undetparams = _undetparams;
def undetparams_=(ps: List[Symbol]) = {
- System.out.println("undetparams = " + ps);
+ //System.out.println("undetparams = " + ps);//debug
_undetparams = ps
}
- def make(unit: CompilationUnit, tree: Tree, owner: Symbol, scope: Scope): Context = {
- val c = new Context();
+ def make(unit: CompilationUnit, tree: Tree, owner: Symbol, scope: Scope, imports: List[ImportInfo]): Context = {
+ val c = new Context;
c.unit = unit;
c.tree = tree;
c.owner = owner;
@@ -66,25 +72,55 @@ class Contexts: Analyzer {
case _ => this.enclClass
}
c.variance = this.variance;
- c.depth = this.depth + 1;
+ c.depth = if (scope == this.scope) this.depth else this.depth + 1;
+ c.imports = imports;
+ c.reportAmbiguousErrors = this.reportAmbiguousErrors;
+ c.reportGeneralErrors = this.reportGeneralErrors;
c.outer = this;
c
}
- def make(unit: CompilationUnit): Context =
- make(unit, EmptyTree, this.owner, this.scope);
+ def make(unit: CompilationUnit): Context = {
+ val c = make(unit, EmptyTree, owner, scope, imports);
+ c.reportAmbiguousErrors = true;
+ c.reportGeneralErrors = true;
+ c
+ }
+
+ def makeNewImport(imp: Import): Context =
+ make(unit, imp, owner, scope, new ImportInfo(imp, depth) :: imports);
def make(tree: Tree, owner: Symbol, scope: Scope): Context =
- make(this.unit, tree, owner, scope);
+ make(unit, tree, owner, scope, imports);
def makeNewScope(tree: Tree, owner: Symbol): Context =
- make(tree, owner, new Scope(this.scope));
+ make(tree, owner, new Scope(scope));
def make(tree: Tree, owner: Symbol): Context =
- make(tree, owner, this.scope);
+ make(tree, owner, scope);
def make(tree: Tree): Context =
- make(tree, this.owner);
+ make(tree, owner);
+
+ def makeImplicit(reportAmbiguousErrors: boolean) = {
+ val c = make(tree);
+ c.reportAmbiguousErrors = reportAmbiguousErrors;
+ c.reportGeneralErrors = false;
+ c
+ }
+
+ def error(pos: int, msg: String): unit =
+ if (reportGeneralErrors) unit.error(pos, msg)
+ else throw new TypeError(msg);
+
+ def ambiguousError(pos: int, pre: Type, sym1: Symbol, sym2: Symbol, rest: String): unit = {
+ val msg =
+ "ambiguous reference to overloaded definition,\n" +
+ "both " + sym1 + ": " + pre.memberType(sym1) + "\n" +
+ "and " + sym2 + ": " + pre.memberType(sym2) + "\nmatch " + rest;
+ if (reportAmbiguousErrors) unit.error(pos, msg)
+ else throw new TypeError(msg);
+ }
def outerContext(clazz: Symbol): Context = {
var c = this;
@@ -101,30 +137,85 @@ class Contexts: Analyzer {
override def toString(): String = {
if (this == NoContext) "NoContext";
- else tree.toString() + "\n:: " + outer.toString()
+ else owner.toString() + " @ " + tree.toString() + "\n:: " + outer.toString()
}
- private var importsCache: List[ImportInfo] = null;
+ /** Is `sym' accessible as a member of tree `site' with type `pre' in current context?
+ */
+ def isAccessible(sym: Symbol, pre: Type, site: Tree): boolean = {
+
+ /** Are we inside definition of `owner'? */
+ def accessWithin(owner: Symbol): boolean = {
+ var c = this;
+ while (c != NoContext && c.owner != owner) {
+ if (c.outer == null) assert(false, "accessWithin(" + owner + ") " + c);//debug
+ if (c.outer.enclClass == null) assert(false, "accessWithin(" + owner + ") " + c);//debug
+ c = c.outer.enclClass;
+ }
+ c != NoContext;
+ }
+
+ /** Is `clazz' a subclass of an enclosing class? */
+ def isSubClassOfEnclosing(clazz: Symbol): boolean = {
+ var c = this;
+ while (c != NoContext && !clazz.isSubClass(c.owner)) c = c.outer.enclClass;
+ c != NoContext;
+ }
+
+ pre == NoPrefix
+ ||
+ (!sym.hasFlag(PRIVATE | PROTECTED))
+ ||
+ accessWithin(sym.owner) && (!sym.hasFlag(LOCAL) || pre.isInstanceOf[ThisType])
+ ||
+ (!sym.hasFlag(PRIVATE) &&
+ (site.isInstanceOf[Super] ||
+ (pre.widen.symbol.isSubClass(sym.owner) && isSubClassOfEnclosing(pre.widen.symbol))))
+ }
- def imports: List[ImportInfo] = {
- def collectImports(stats: List[Tree]): List[ImportInfo] = stats match {
- case Nil => outer.imports
- case (imp @ Import(_, _)) :: rest => new ImportInfo(imp, depth) :: collectImports(rest)
- case _ :: rest => collectImports(rest)
+ private var implicitsCache: List[List[ImplicitInfo]] = null;
+
+ private def collectImplicits(syms: List[Symbol], pre: Type): List[ImplicitInfo] =
+ for (val sym <- syms; sym.hasFlag(IMPLICIT) && isAccessible(sym, pre, EmptyTree))
+ yield ImplicitInfo(sym.name, pre.memberType(sym), sym);
+
+ private def collectImplicitImports(imp: ImportInfo): List[ImplicitInfo] = {
+ val pre = imp.qual.tpe;
+ def collect(sels: List[Pair[Name, Name]]): List[ImplicitInfo] = sels match {
+ case List() => List()
+ case List(Pair(nme.WILDCARD, _)) => collectImplicits(pre.implicitMembers, pre)
+ case Pair(from, to) :: sels1 =>
+ var impls = collect(sels1) filter (info => info.name != from);
+ if (to != nme.WILDCARD) {
+ val sym = imp.importedSymbol(to);
+ if (sym.hasFlag(IMPLICIT)) impls = ImplicitInfo(to, pre.memberType(sym), sym) :: impls;
+ }
+ impls
}
- if (importsCache == null) {
- importsCache = tree match {
- case PackageDef(_, stats) => collectImports(stats)
- case Template(_, stats) => collectImports(stats)
- case Block(stats, _) => collectImports(stats)
- case _ => outer.imports
- }
+ if (settings.debug.value) System.out.println("collect implicit imports " + imp + "=" + collect(imp.tree.selectors));//debug
+ collect(imp.tree.selectors)
+ }
+
+ def implicitss: List[List[ImplicitInfo]] = {
+ if (implicitsCache == null) {
+ val newImplicits: List[ImplicitInfo] =
+ if (owner != outer.owner && owner.isClass && !owner.isPackageClass) {
+ collectImplicits(owner.info.implicitMembers, owner.thisType)
+ } else if (scope != outer.scope && !owner.isPackageClass) {
+ if (settings.debug.value) System.out.println("collect local implicits " + scope.toList);//debug
+ collectImplicits(scope.toList, NoPrefix)
+ } else if (imports != outer.imports) {
+ assert(imports.tail == outer.imports);
+ collectImplicitImports(imports.head)
+ } else List();
+ implicitsCache = if (newImplicits.isEmpty) outer.implicitss
+ else newImplicits :: outer.implicitss;
}
- importsCache
+ implicitsCache
}
}
- class ImportInfo(tree: Import, val depth: int) {
+ class ImportInfo(val tree: Import, val depth: int) {
/** The prefix expression */
def qual: Tree = tree.symbol.info match {
@@ -144,12 +235,12 @@ class Contexts: Analyzer {
var selectors = tree.selectors;
while (selectors != Nil && result == NoSymbol) {
if (selectors.head._2 == name.toTermName)
- result = tree.expr.symbol.info.member(
+ result = qual.tpe.member(
if (name.isTypeName) selectors.head._1.toTypeName else selectors.head._1);
else if (selectors.head._1 == name.toTermName)
renamed = true
else if (selectors.head._1 == nme.WILDCARD && !renamed)
- result = tree.expr.symbol.info.member(name);
+ result = qual.tpe.member(name);
selectors = selectors.tail
}
result
@@ -159,6 +250,6 @@ class Contexts: Analyzer {
}
case class ImportType(expr: Tree) extends Type;
-}
-
+ case class ImplicitInfo(val name: Name, val tpe: Type, val sym: Symbol);
+}