diff options
author | Martin Odersky <odersky@gmail.com> | 2005-04-28 17:37:27 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2005-04-28 17:37:27 +0000 |
commit | 0baff379fd40abb757551c7a02676b051b1c8e17 (patch) | |
tree | 7352cfd392c87bd78781a66a74df0e00346c829e /sources/scala/tools/nsc/typechecker/Contexts.scala | |
parent | 6d81466523463b6a7795e841a7cfdf7ad3e06356 (diff) | |
download | scala-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-x | sources/scala/tools/nsc/typechecker/Contexts.scala | 165 |
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); +} |