diff options
author | Sean McDirmid <sean.mcdirmid@gmail.com> | 2007-09-17 16:36:10 +0000 |
---|---|---|
committer | Sean McDirmid <sean.mcdirmid@gmail.com> | 2007-09-17 16:36:10 +0000 |
commit | a205b6b06e705711308c9ad3abac74ba66b6266f (patch) | |
tree | 49aa189b4917b20d76c2da02cbf9475af5a49662 /src/compiler/scala/tools/nsc/typechecker | |
parent | 3f9b82c88d74c1b03daf5131b50c172213f40a63 (diff) | |
download | scala-a205b6b06e705711308c9ad3abac74ba66b6266f.tar.gz scala-a205b6b06e705711308c9ad3abac74ba66b6266f.tar.bz2 scala-a205b6b06e705711308c9ad3abac74ba66b6266f.zip |
Massive check-in for IDE.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker')
8 files changed, 558 insertions, 281 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index 6d95b1a762..1ec4da1a54 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -26,7 +26,7 @@ trait Analyzer extends AnyRef val phaseName = "namer" def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) { def apply(unit: CompilationUnit): unit = - new Namer(rootContext(unit)).enterSym(unit.body) + newNamer(rootContext(unit)).enterSym(unit.body) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 734c29e2cf..ee1637c65a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -86,9 +86,12 @@ trait Contexts { self: Analyzer => sc = sc.outer } } - class Context { + // IDE hooks + protected def sanitize(tree : Tree) : Tree = tree + protected def scopeFor(old : Scope, tree : Tree) : Scope = newScope(old) + class Context private[typechecker] { var unit: CompilationUnit = _ - var tree: Tree = _ // Tree associated with this context + var tree: Tree = _ // Tree associated with this context var owner: Symbol = NoSymbol// The current owner var scope: Scope = _ // The current scope var outer: Context = _ // The next outer context @@ -113,39 +116,88 @@ trait Contexts { self: Analyzer => var savedTypeBounds: List[(Symbol, Type)] = List() - override def equals(that : Any) = that match { - case that if (super.equals(that)) => true - case NoContext => false + + def intern0 : Context = { + if (this eq NoContext) return this + val txt = new Context + txt.unit = unit + txt.tree = tree + txt.owner = owner + txt.scope = scope + assert(outer ne this) // stupid + txt.outer = outer // already interned + def f(what : Context) = + if (what eq this) txt + else what + txt.enclClass = f(enclClass) + txt.enclMethod = f(enclMethod) + txt.implicitsEnabled = implicitsEnabled + txt.variance = variance + txt._undetparams = _undetparams + txt.depth = depth + txt.imports = imports + txt.prefix = prefix + txt.inConstructorSuffix = inConstructorSuffix + txt.returnsSeen = returnsSeen + txt.reportGeneralErrors = reportGeneralErrors + txt.checking = checking + txt.retyping = retyping + txt.savedTypeBounds = savedTypeBounds + txt + } + override def equals(that : Any) : Boolean = that match { + case that : AnyRef if (this eq that) => true + case that if !inIDE => super.equals(that) + //case NoContext => false case that : Context => - val a0 = if (tree eq null) tree == that.tree else tree equalsStructure that.tree; - val a1 = owner == that.owner - val a2 = scope == that.scope - val a3 = outer == that.outer - val a4 = { - if (enclClass eq this) { - that.enclClass eq that; - } else enclClass == that.enclClass; + if (that eq NoContext) return this eq NoContext + assert(that ne NoContext) + if (this eq NoContext) return false + assert(inIDE) + def eq[T](x : T, y : T) = x == y + val a0 = { + if (tree ne null) tree.setType(null) + if ((tree eq null) || (that.tree eq null)) tree == that.tree else + tree equalsStructure that.tree; + } + val a1 = eq(owner, that.owner) + val a2 = eq(scope, that.scope) + def f(txt0 : Context, txt1 : Context) = + ((this eq txt0) && (that eq txt1)) || (txt0 eq txt1) + + val a3 = f(outer, that.outer) + val a4 = f(enclClass, that.enclClass) + val a5 = f(enclMethod, that.enclMethod) + val a6 = eq(variance, that.variance) + val a7 = eq(_undetparams, that._undetparams) + val a8 = eq(depth, that.depth) + val a9 = eq(imports, that.imports) + + val a10 = eq(prefix, that.prefix) + val a11 = eq(inConstructorSuffix, that.inConstructorSuffix) + val a12 = eq(implicitsEnabled, that.implicitsEnabled) + val a13 = eq(checking, that.checking) + val a14 = eq(retyping, that.retyping) + val a15 = eq(savedTypeBounds, that.savedTypeBounds) + val a16 = eq(unit, that.unit) + val ret = a0 && a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8 && a9 && a10 && a11 && a12 && a13 && a14 && a15 && a16 + val a17 = { + if (implicitsRunId > that.implicitsRunId) { + that.implicitsRunId = NoRunId + that.implicitsCache = null + } + else if (that.implicitsRunId > implicitsRunId) { + implicitsRunId = NoRunId + implicitsCache = null + } + implicitsCache == that.implicitsCache } - val a5 = { - if (enclMethod eq this) - that.enclMethod eq that; - else enclMethod == that.enclMethod; + if (ret) { + if (!a17) { + assert(this.implicitsCache == null || that.implicitsCache == null) + } } - val a6 = variance == that.variance; - val a7 = _undetparams == that._undetparams; - val a8 = depth == that.depth; - val a9 = if (imports.length != that.imports.length) false else - (for (x <- imports.zip(that.imports)) yield - (x._1.tree equalsStructure x._2.tree) && x._1.depth == x._2.depth). - foldLeft(true)((x,y) => x && y); - - val a10 = prefix == that.prefix - val a11 = inConstructorSuffix == that.inConstructorSuffix - val a12 = implicitsEnabled == that.implicitsEnabled - val a13 = checking == that.checking - val a14 = retyping == that.retyping - val a15 = savedTypeBounds == that.savedTypeBounds - a0 && a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8 && a9 && a10 && a11 && a12 && a13 && a14 && a15 + ret case _ => false } @@ -168,16 +220,23 @@ trait Contexts { self: Analyzer => scope: Scope, imports: List[ImportInfo]): Context = { val c = new Context c.unit = unit - c.tree = tree + c.tree = sanitize(tree) c.owner = owner c.scope = scope + + c.outer = intern(this) + def internIf(txt : Context) = { + if (txt eq this) c.outer // already interned! + else txt + } + tree match { case Template(_, _, _) | PackageDef(_, _) => c.enclClass = c c.prefix = c.owner.thisType c.inConstructorSuffix = false case _ => - c.enclClass = this.enclClass + c.enclClass = internIf(this.enclClass) c.prefix = if (c.owner != this.owner && c.owner.isTerm) NoPrefix else this.prefix @@ -187,7 +246,7 @@ trait Contexts { self: Analyzer => case DefDef(_, _, _, _, _, _) => c.enclMethod = c case _ => - c.enclMethod = this.enclMethod + c.enclMethod = internIf(this.enclMethod) } c.variance = this.variance c.depth = if (scope == this.scope) this.depth else this.depth + 1 @@ -197,7 +256,6 @@ trait Contexts { self: Analyzer => c.implicitsEnabled = this.implicitsEnabled c.checking = this.checking c.retyping = this.retyping - c.outer = this c } @@ -212,14 +270,21 @@ trait Contexts { self: Analyzer => def makeNewImport(imp: Import): Context = make(unit, imp, owner, scope, new ImportInfo(imp, depth) :: imports) - def make(tree: Tree, owner: Symbol, scope: Scope): Context = + + + def make(tree: Tree, owner: Symbol, scope: Scope): Context = { + if (tree == this.tree && owner == this.owner && scope == this.scope) this + else make0(tree, owner, scope) + } + private def make0(tree : Tree, owner : Symbol, scope : Scope) : Context = { make(unit, tree, owner, scope, imports) + } def makeNewScope(tree: Tree, owner: Symbol): Context = - make(tree, owner, newScope(scope)) + make(tree, owner, scopeFor(scope, tree)) def make(tree: Tree, owner: Symbol): Context = - make(tree, owner, scope) + make0(tree, owner, scope) def make(tree: Tree): Context = make(tree, owner) @@ -242,7 +307,7 @@ trait Contexts { self: Analyzer => //todo: find out why we need next line while (baseContext.tree.isInstanceOf[Template]) baseContext = baseContext.outer - val argContext = Contexts.this.makeNewScope(baseContext, tree, owner) + val argContext = baseContext.makeNewScope(tree, owner) argContext.reportGeneralErrors = this.reportGeneralErrors argContext.reportAmbiguousErrors = this.reportAmbiguousErrors def enterElems(c: Context) { @@ -364,6 +429,8 @@ trait Contexts { self: Analyzer => def accessWithin(owner: Symbol): Boolean = { var c = this while (c != NoContext && c.owner != owner) { + if (false && inIDE) // XXX: we didn't get to update these syms.... + assert(c.owner.fullNameString != owner.fullNameString) if (c.outer eq null) assert(false, "accessWithin(" + owner + ") " + c);//debug if (c.outer.enclClass eq null) assert(false, "accessWithin(" + owner + ") " + c);//debug c = c.outer.enclClass @@ -422,6 +489,11 @@ trait Contexts { self: Analyzer => private var implicitsCache: List[List[ImplicitInfo]] = null private var implicitsRunId = NoRunId + def resetCache : Unit = { + implicitsRunId = NoRunId + implicitsCache = null + if (outer != null && outer != this) outer.resetCache + } private def collectImplicits(syms: List[Symbol], pre: Type): List[ImplicitInfo] = for (sym <- syms if sym.hasFlag(IMPLICIT) && isAccessible(sym, pre, false)) yield new ImplicitInfo(sym.name, pre, sym) @@ -473,10 +545,33 @@ trait Contexts { self: Analyzer => } implicitsCache } - } + override def hashCode = { + var hc = 0 + implicit def b2i(b : Boolean) = if (b) 1 else 0 + // assum enclClass/enclMethod/outer are all interned already. + hc += tree.hashCodeStructure + def f(txt : Context) = if (txt eq this) 0 else System.identityHashCode(txt) + hc += f(enclClass) + hc += f(enclMethod) + hc += f(outer) + hc += owner.hashCode + hc += scope.hashCode + hc += variance.hashCode + hc += _undetparams.hashCode + hc += depth + hc += imports.hashCode + hc += prefix.hashCode + hc += inConstructorSuffix + hc += checking + hc += retyping + hc += savedTypeBounds.hashCode + hc += (if (unit eq null) 0 else unit.hashCode) + hc + } + } + def notifyImport(what : Name, container : Type, from : Name, to : Name) : Unit = {} class ImportInfo(val tree: Import, val depth: Int) { - /** The prefix expression */ def qual: Tree = tree.symbol.info match { case ImportType(expr) => expr @@ -495,6 +590,9 @@ trait Contexts { self: Analyzer => var renamed = false var selectors = tree.selectors while (selectors != Nil && result == NoSymbol) { + if (selectors.head._1 != nme.WILDCARD) + notifyImport(name, qual.tpe, selectors.head._1, selectors.head._2) + if (selectors.head._2 == name.toTermName) result = qual.tpe.member( if (name.isTypeName) selectors.head._1.toTypeName else selectors.head._1) @@ -508,6 +606,13 @@ trait Contexts { self: Analyzer => } override def toString() = tree.toString() + + override def hashCode = tree.hashCodeStructure + depth + override def equals(that : Any) = that match { + case that : ImportInfo => + depth == that.depth && (tree equalsStructure that.tree) + case _ => false + } } class ImplicitInfo(val name: Name, val pre: Type, val sym: Symbol) { @@ -521,5 +626,31 @@ trait Contexts { self: Analyzer => val NoImplicitInfo = new ImplicitInfo(null, null, null) - case class ImportType(expr: Tree) extends Type + case class ImportType(expr: Tree) extends Type { + override def equals(that : Any) = that match { + case ImportType(expr) => + if (inIDE) this.expr equalsStructure expr + else this.expr == expr + case _ => false + } + override def hashCode = if (inIDE) expr.hashCodeStructure else expr.hashCode + } + + /* APIs for interning contexts */ + import scala.collection.jcl + import scala.ref + protected def intern(txt : Context) = txt + class ContextInternMap extends jcl.WeakHashMap[Context,ref.WeakReference[Context]] { + var last : Context = _ + override def default(txt : Context) : ref.WeakReference[Context] = { + if (txt eq NoContext) new ref.WeakReference(NoContext) + val txt0 = txt.intern0 + last = txt0 // to prevent collection + val ret = new ref.WeakReference(txt0) + this(txt0) = ret + ret + } + def intern(txt : Context) = this(txt).get.get + } + } diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala index 1cdcf6210a..938a07f5bf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -34,10 +34,21 @@ trait EtaExpansion { self: Analyzer => * tree is already attributed * </p> */ - def etaExpand(tree: Tree): Tree = { + def etaExpand(unit : CompilationUnit, tree: Tree): Tree = { val tpe = tree.tpe - var cnt = 0 - def freshName() = { cnt = cnt + 1; newTermName("eta$" + cnt) } + val symbolHash = if (!inIDE) "" else Integer.toString(tree.symbol.hashCode, 10 + ('z' - 'a')) + "$" + var cnt = 0 // for NoPosition + def freshName(pos : util.Position, n : Int) = { + cnt += 1 + if (pos == util.NoPosition) { + newTermName("eta$" + symbolHash + (cnt - 1)) + } else if (n == 0) { + newTermName(unit.fresh.newName(pos, "eta$" + symbolHash)) + } else { + newTermName(unit.fresh.newName(pos, "eta$" + symbolHash + n + "$")) + } + } + // { cnt = cnt + 1; newTermName("eta$" + cnt) } val defs = new ListBuffer[Tree] /** Append to <code>defs</code> value definitions for all non-stable @@ -50,7 +61,7 @@ trait EtaExpansion { self: Analyzer => def liftout(tree: Tree): Tree = if (treeInfo.isPureExpr(tree)) tree else { - val vname: Name = freshName() + val vname: Name = freshName(tree.pos, 0) defs += atPos(tree.pos)(ValDef(Modifiers(SYNTHETIC), vname, TypeTree(), tree)) Ident(vname) setPos tree.pos } @@ -76,8 +87,13 @@ trait EtaExpansion { self: Analyzer => case mt: ImplicitMethodType => tree case MethodType(formals, restpe) => + var cnt0 = 0 + def cnt = { + cnt0 += 1 + cnt0 - 1 + } val params = formals map (formal => - ValDef(Modifiers(SYNTHETIC | PARAM), freshName(), TypeTree() + ValDef(Modifiers(SYNTHETIC | PARAM), freshName(tree.pos, cnt), TypeTree() .setType(formal), EmptyTree)) val args = params map (param => Ident(param.name)) val applyArgs = diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index b79fca75f9..015c0636c8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -245,7 +245,7 @@ trait Infer { private def withDisambiguation[T](tp1: Type, tp2: Type)(op: => T): T = { def explainName(sym: Symbol) = { - if (!sym.name.toString.endsWith(")")) { + if (!sym.name.toString.endsWith(")") && !inIDE) { sym.name = newTypeName(sym.name.toString+"(in "+sym.owner+")") } } @@ -259,7 +259,7 @@ trait Infer { val name = sym1.name explainName(sym1) explainName(sym2) - if (sym1.owner == sym2.owner) sym2.name = newTypeName("(some other)"+sym2.name) + if (sym1.owner == sym2.owner && !inIDE) sym2.name = newTypeName("(some other)"+sym2.name) patches += (sym1, sym2, name) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 9138b2d412..a6409c6398 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -39,14 +39,18 @@ trait Namers { self: Analyzer => } } /** overridden by IDE to not manually enter value parameters */ - protected final def doEnterValueParams = !inIDE; - protected def inIDE = false; + protected final def doEnterValueParams = true // !inIDE; + // can't use the other ones. + protected def newDecls(classSym : Symbol) : Scope = newClassScope - class Namer(val context: Context) { + private class NormalNamer(context : Context) extends Namer(context) + def newNamer(context : Context) : Namer = new NormalNamer(context) + + abstract class Namer(val context: Context) { val typer = newTyper(context) - def setPrivateWithin(tree: Tree, sym: Symbol, mods: Modifiers): Symbol = { + def setPrivateWithin[Sym <: Symbol](tree: Tree, sym: Sym, mods: Modifiers): Sym = { if (!mods.privateWithin.isEmpty) sym.privateWithin = typer.qualifyingClassContext(tree, mods.privateWithin).owner sym @@ -75,6 +79,10 @@ trait Namers { self: Analyzer => } private var innerNamerCache: Namer = null + protected def makeConstructorScope(classContext : Context) : Context = { + val outerContext = classContext.outer.outer + outerContext.makeNewScope(outerContext.tree, outerContext.owner) + } def namerOf(sym: Symbol): Namer = { @@ -82,46 +90,51 @@ trait Namers { self: Analyzer => if (innerNamerCache eq null) innerNamerCache = if (!isTemplateContext(context)) this - else new Namer(context.make(context.tree, context.owner, newScope)) + else newNamer(context.make(context.tree, context.owner, scopeFor(context.tree))) innerNamerCache } def primaryConstructorParamNamer: Namer = { //todo: can we merge this with SCCmode? val classContext = context.enclClass - val outerContext = classContext.outer.outer - val paramContext = outerContext.makeNewScope(outerContext.tree, outerContext.owner) - classContext.owner.unsafeTypeParams foreach(sym => paramContext.scope.enter(sym)) - new Namer(paramContext) - } - - if (sym.isTerm && - (sym.hasFlag(PARAM) && sym.owner.isPrimaryConstructor || sym.hasFlag(PARAMACCESSOR))) - primaryConstructorParamNamer - else - innerNamer + val paramContext = makeConstructorScope(classContext) + val unsafeTypeParams = context.owner.unsafeTypeParams + unsafeTypeParams foreach(sym => paramContext.scope.enter(sym)) + newNamer(paramContext) + } + if (sym.isTerm) { + if (sym.hasFlag(PARAM) && sym.owner.isPrimaryConstructor) + primaryConstructorParamNamer + else if (sym.hasFlag(PARAMACCESSOR) && !inIDE) + primaryConstructorParamNamer + else innerNamer + } else innerNamer } + protected def conflict(newS : Symbol, oldS : Symbol) : Boolean = { + (!oldS.isSourceMethod || + nme.isSetterName(newS.name) || + newS.owner.isPackageClass) && + !((newS.owner.isTypeParameter || newS.owner.isAbstractType) && + newS.name.length==1 && newS.name(0)=='_') //@M: allow repeated use of `_' for higher-order type params + } + protected def setInfo[Sym <: Symbol](sym : Sym)(tpe : LazyType) : Sym = sym.setInfo(tpe) private def doubleDefError(pos: Position, sym: Symbol) { context.error(pos, sym.name.toString() + " is already defined as " + (if (sym.hasFlag(CASE)) "case class " + sym.name else sym.toString())) } - def enterInScope[A <: Symbol](sym: A): A = { + def enterInScope(sym: Symbol): Symbol = { // allow for overloaded methods if (!(sym.isSourceMethod && sym.owner.isClass && !sym.owner.isPackageClass)) { val prev = context.scope.lookupEntry(sym.name); - if ((prev ne null) && prev.owner == context.scope && - (!prev.sym.isSourceMethod || - nme.isSetterName(sym.name) || - sym.owner.isPackageClass) && - !((sym.owner.isTypeParameter || sym.owner.isAbstractType) - && sym.name.length==1 && sym.name(0)=='_')) { //@M: allow repeated use of `_' for higher-order type params + if ((prev ne null) && prev.owner == context.scope && conflict(sym, prev.sym)) { doubleDefError(sym.pos, prev.sym) - sym setInfo ErrorType + if (!inIDE) sym setInfo ErrorType // don't do this in IDE for stability + context.scope unlink prev.sym + context.scope enter sym } else context.scope enter sym } else context.scope enter sym - sym } def enterPackageSymbol(pos: Position, name: Name): Symbol = { @@ -133,79 +146,102 @@ trait Namers { self: Analyzer => } else { val cowner = if (context.owner == EmptyPackageClass) RootClass else context.owner val pkg = cowner.newPackage(pos, name) - pkg.moduleClass.setInfo(new PackageClassInfoType(newScope, pkg.moduleClass)) + // IDE: newScope should be ok because packages are never destroyed. + if (inIDE) assert(pkg.moduleClass.rawInfoSafe.isEmpty || !pkg.moduleClass.rawInfo.isComplete) + pkg.moduleClass.setInfo(new PackageClassInfoType(newScope, pkg.moduleClass, null)) pkg.setInfo(pkg.moduleClass.tpe) enterInScope(pkg) } } - def inConstructorFlag: long = + def inConstructorFlag: Long = if (context.owner.isConstructor && !context.inConstructorSuffix || context.owner.isEarly) INCONSTRUCTOR else 0l - private def enterClassSymbol(pos: Position, flags: long, name: Name): Symbol = { - var c: Symbol = context.scope.lookup(name) - if (c.isType && !currentRun.compiles(c) && context.scope == c.owner.info.decls) { - updatePosFlags(c, pos, flags) + def enterClassSymbol(tree : ClassDef): Symbol = { + var c: Symbol = context.scope.lookup(tree.name); + // Never take the first path in the IDE because we could be completing c.owner's type! + // the other path will handle symbol re-use well enough. + if (!inIDE && c.isType && context.scope == c.owner.info.decls && !currentRun.compiles(c)) { + updatePosFlags(c, tree.pos, tree.mods.flags) + setPrivateWithin(tree, c, tree.mods) } else { - c = enterInScope(context.owner.newClass(pos, name)).setFlag(flags | inConstructorFlag) + //if (inIDE && c != NoSymbol) currentRun.compiles(c) // in IDE, will unload/save non-source symbol + var sym = context.owner.newClass(tree.pos, tree.name) + sym = sym.setFlag(tree.mods.flags | inConstructorFlag) + sym = setPrivateWithin(tree, sym, tree.mods) + c = enterInScope(sym) } if (c.owner.isPackageClass) { - val file = context.unit.source.getFile() + val file = context.unit.source.file val clazz = c.asInstanceOf[ClassSymbol] if (settings.debug.value && (clazz.sourceFile ne null) && !clazz.sourceFile.equals(file)) { Console.err.println("SOURCE MISMATCH: " + clazz.sourceFile + " vs. " + file + " SYM=" + c); } clazz.sourceFile = file if (clazz.sourceFile ne null) { - assert(!currentRun.compiles(clazz) || clazz.sourceFile == currentRun.symSource(c)); + assert(inIDE || !currentRun.compiles(clazz) || clazz.sourceFile == currentRun.symSource(c)); currentRun.symSource(c) = clazz.sourceFile } } + assert(c.name.toString.indexOf('(') == -1) c } - - private def enterModuleSymbol(pos: Position, flags: long, name: Name): Symbol = { - var m: Symbol = context.scope.lookup(name) - if (m.isModule && !m.isPackage && !currentRun.compiles(m) && - (context.scope == m.owner.info.decls)) { - updatePosFlags(m, pos, flags) + def enterModuleSymbol(tree : ModuleDef): Symbol = { + // .pos, mods.flags | MODULE | FINAL, name + assert(tree.name.isTermName) + var m: Symbol = context.scope.lookup(tree.name) + if (!inIDE && m.isModule && !m.isPackage && (context.scope == m.owner.info.decls) && + !currentRun.compiles(m)) { + updatePosFlags(m, tree.pos, tree.mods.flags|MODULE|FINAL) + setPrivateWithin(tree, m, tree.mods) } else { - if (m.isTerm && !m.isPackage && !currentRun.compiles(m) && (context.scope == m.owner.info.decls)) + if (m.isTerm && !m.isPackage && currentRun.compiles(m) && (context.scope == m.owner.info.decls)) context.scope.unlink(m) - m = context.owner.newModule(pos, name) - m.setFlag(flags) - m.moduleClass.setFlag(flags | inConstructorFlag) - enterInScope(m) + + m = context.owner.newModule(tree.pos, tree.name) + m.setFlag(tree.mods.flags) + m = setPrivateWithin(tree, m, tree.mods) + m = enterInScope(m) + + m.moduleClass.setFlag(tree.mods.flags|MODULE|FINAL| inConstructorFlag) + setPrivateWithin(tree, m.moduleClass, tree.mods) } if (m.owner.isPackageClass) { - m.moduleClass.sourceFile = context.unit.source.getFile() + m.moduleClass.sourceFile = context.unit.source.file currentRun.symSource(m) = m.moduleClass.sourceFile } m } - private def enterCaseFactorySymbol(pos: Position, flags: long, name: Name): Symbol = { + def enterCaseFactorySymbol(tree : ClassDef): Symbol = { + val pos = tree.pos + val flags = tree.mods.flags & AccessFlags | METHOD | CASE + val name = tree.name.toTermName var m: Symbol = context.scope.lookup(name) - if (m.isTerm && !m.isPackage && !currentRun.compiles(m) && context.scope == m.owner.info.decls) { + if (!inIDE && m.isTerm && !m.isPackage && !currentRun.compiles(m) && context.scope == m.owner.info.decls) { updatePosFlags(m, pos, flags) + setPrivateWithin(tree, m, tree.mods) } else { - m = enterInScope(context.owner.newMethod(pos, name)).setFlag(flags) + // recycle the old fashion way. + m = enterInScope{ + var sym = context.owner.newMethod(pos, name).setFlag(flags) + sym = setPrivateWithin(tree, sym, tree.mods) + sym + } } if (m.owner.isPackageClass) - currentRun.symSource(m) = context.unit.source.getFile() + currentRun.symSource(m) = context.unit.source.file m } - def enterSyms(trees: List[Tree]): Namer = { var namer : Namer = this for (tree <- trees) { val txt = namer.enterSym(tree) - if (!(txt eq namer.context)) namer = new Namer(txt) + if (!(txt eq namer.context)) namer = newNamer(txt) } namer } - def newTypeSkolems(tparams: List[Symbol]): List[Symbol] = { val tskolems = tparams map (_.newTypeSkolem) val ltp = new LazyType { @@ -216,7 +252,6 @@ trait Namers { self: Analyzer => tskolems foreach (_.setInfo(ltp)) tskolems } - /** Replace type parameters with their TypeSkolems, which can later be deskolemized to the original type param * (a skolem is a representation of a bound variable when viewed outside its scope) */ @@ -237,10 +272,15 @@ trait Namers { self: Analyzer => override val typeParams: List[Symbol]= tparams map (_.symbol) //@M override def complete(sym: Symbol) { if(ownerSym.isAbstractType) //@M an abstract type's type parameters are entered -- TODO: change to isTypeMember ? - new Namer(ctx.makeNewScope(owner, ownerSym)).enterSyms(tparams) //@M + newNamer(ctx.makeNewScope(owner, ownerSym)).enterSyms(tparams) //@M restp.complete(sym) } } + def reuse[T <: Tree](tree: T) = if (!inIDE) tree else { + val tree0 = tree.duplicate + //tree0.symbol = tree.symbol + tree0 + } def enterSym(tree: Tree): Context = { @@ -253,11 +293,11 @@ trait Namers { self: Analyzer => //@M e.g., in [A[x <: B], B], A and B are entered first as both are in scope in the definition of x //@M x is only in scope in `A[x <: B]' if(!sym.isAbstractType) //@M TODO: change to isTypeMember ? - new Namer(context.makeNewScope(tree, sym)).enterSyms(tparams) + newNamer(context.makeNewScope(tree, sym)).enterSyms(tparams) ltype = new LazyPolyType(tparams, ltype, tree, sym, context) //@M if (sym.isTerm) skolemize(tparams) } - sym.setInfo(ltype) + setInfo(sym)(ltype) } def finish = finishWith(List()) @@ -267,45 +307,43 @@ trait Namers { self: Analyzer => tree match { case PackageDef(name, stats) => tree.symbol = enterPackageSymbol(tree.pos, name) - val namer = new Namer( + val namer = newNamer( context.make(tree, tree.symbol.moduleClass, tree.symbol.info.decls)) namer.enterSyms(stats) - case ClassDef(mods, name, tparams, impl) => + case tree @ ClassDef(mods, name, tparams, impl) => + tree.symbol = enterClassSymbol(tree) + finishWith(tparams) if ((mods.flags & CASE) != 0) { // enter case factory method. - tree.symbol = enterCaseFactorySymbol( - tree.pos, mods.flags & AccessFlags | METHOD | CASE, name.toTermName) - tree.symbol.setInfo(namerOf(tree.symbol).caseFactoryCompleter(tree)) - setPrivateWithin(tree, tree.symbol, mods) + val sym = enterCaseFactorySymbol(tree) + setInfo(sym)(namerOf(sym).caseFactoryCompleter(reuse(tree))) } - tree.symbol = enterClassSymbol(tree.pos, mods.flags, name) - setPrivateWithin(tree, tree.symbol, mods) - finishWith(tparams) - case ModuleDef(mods, name, _) => - tree.symbol = enterModuleSymbol(tree.pos, mods.flags | MODULE | FINAL, name) - setPrivateWithin(tree, tree.symbol, mods) - setPrivateWithin(tree, tree.symbol.moduleClass, mods) - tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter(tree)) + case tree @ ModuleDef(mods, name, _) => + tree.symbol = enterModuleSymbol(tree) + // IDE: do not use the setInfo call for the module class as it is initialized + // through module symbol + tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter(reuse(tree))) finish + case ValDef(mods, name, tp, rhs) => if (context.owner.isClass && (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL) || (mods.flags & LAZY) != 0) { val accflags: Long = ACCESSOR | (if ((mods.flags & MUTABLE) != 0) mods.flags & ~MUTABLE & ~PRESUPER else mods.flags & ~PRESUPER | STABLE) - val getter = owner.newMethod(tree.pos, name).setFlag(accflags) - getter.setInfo(namerOf(getter).getterTypeCompleter(tree)) + var getter = owner.newMethod(tree.pos, name).setFlag(accflags) setPrivateWithin(tree, getter, mods) - enterInScope(getter) + getter = enterInScope(getter).asInstanceOf[TermSymbol] + setInfo(getter)(namerOf(getter).getterTypeCompleter(tree)) if ((mods.flags & MUTABLE) != 0) { - val setter = owner.newMethod(tree.pos, nme.getterToSetter(name)) + var setter = owner.newMethod(tree.pos, nme.getterToSetter(name)) .setFlag(accflags & ~STABLE & ~CASEACCESSOR) - setter.setInfo(namerOf(setter).setterTypeCompleter(tree)) setPrivateWithin(tree, setter, mods) - enterInScope(setter) + setter = enterInScope(setter).asInstanceOf[TermSymbol] + setInfo(setter)(namerOf(setter).setterTypeCompleter(tree)) } tree.symbol = - if ((mods.flags & DEFERRED) == 0) { - val vsym = + if ((mods.flags & DEFERRED) == 0) { // not deferred + var vsym = if (!context.owner.isClass) { assert((mods.flags & LAZY) != 0) // if not a field, it has to be a lazy val owner.newValue(tree.pos, name + "$lzy" ).setFlag(mods.flags | MUTABLE) @@ -313,39 +351,39 @@ trait Namers { self: Analyzer => owner.newValue(tree.pos, nme.getterToLocal(name)) .setFlag(mods.flags & FieldFlags | PRIVATE | LOCAL | (if ((mods.flags & LAZY) != 0) MUTABLE else 0)) } - val value = enterInScope(vsym) - value.setInfo(namerOf(value).typeCompleter(tree)) + vsym = enterInScope(vsym).asInstanceOf[TermSymbol] + setInfo(vsym)(namerOf(vsym).typeCompleter(tree)) if ((mods.flags & LAZY) != 0) - value.setLazyAccessor(getter) - value + vsym.setLazyAccessor(getter) + vsym } else getter; } else { - tree.symbol = enterInScope(owner.newValue(tree.pos, name)) - .setFlag(mods.flags) + tree.symbol = enterInScope(owner.newValue(tree.pos, name) + .setFlag(mods.flags)) finish } case DefDef(mods, nme.CONSTRUCTOR, tparams, _, _, _) => - tree.symbol = enterInScope(owner.newConstructor(tree.pos)) - .setFlag(mods.flags | owner.getFlag(ConstrFlags)) - setPrivateWithin(tree, tree.symbol, mods) + var sym = owner.newConstructor(tree.pos).setFlag(mods.flags | owner.getFlag(ConstrFlags)) + setPrivateWithin(tree, sym, mods) + tree.symbol = enterInScope(sym) finishWith(tparams) case DefDef(mods, name, tparams, _, _, _) => - tree.symbol = enterInScope(owner.newMethod(tree.pos, name)) - .setFlag(mods.flags) - setPrivateWithin(tree, tree.symbol, mods) + var sym = (owner.newMethod(tree.pos, name)).setFlag(mods.flags) + setPrivateWithin(tree, sym, mods) + tree.symbol = enterInScope(sym) finishWith(tparams) case TypeDef(mods, name, tparams, _) => var flags: Long = mods.flags if ((flags & PARAM) != 0) flags |= DEFERRED - tree.symbol = enterInScope(new TypeSymbol(owner, tree.pos, name)) - .setFlag(flags) - setPrivateWithin(tree, tree.symbol, mods) + var sym =new TypeSymbol(owner, tree.pos, name).setFlag(flags) + setPrivateWithin(tree, sym, mods) + tree.symbol = enterInScope(sym) finishWith(tparams) case DocDef(_, defn) => enterSym(defn) case imp @ Import(_, _) => tree.symbol = NoSymbol.newImport(tree.pos) - tree.symbol.setInfo(namerOf(tree.symbol).typeCompleter(tree)) + setInfo(tree.symbol)(namerOf(tree.symbol).typeCompleter(tree)) return (context.makeNewImport(imp)) case _ => } @@ -451,11 +489,20 @@ trait Namers { self: Analyzer => def enterValueParams(owner: Symbol, vparamss: List[List[ValDef]]): List[List[Symbol]] = { def enterValueParam(param: ValDef): Symbol = if (doEnterValueParams) { - param.symbol = owner.newValueParameter(param.pos, param.name) - .setInfo(typeCompleter(param)) - .setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT)) - setPrivateWithin(param, param.symbol, param.mods) - enterInScope(param.symbol) + if (inIDE) param.symbol = { + var sym = owner.newValueParameter(param.pos, param.name). + setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT)) + setPrivateWithin(param, sym, param.mods) + sym = enterInScope(sym).asInstanceOf[TermSymbol] + if (!sym.rawInfoSafe.isDefined || sym.rawInfo.isComplete) + setInfo(sym)(typeCompleter(param)) + sym + } else param.symbol = setInfo( + enterInScope{ + val sym = owner.newValueParameter(param.pos, param.name). + setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT)) + setPrivateWithin(param, sym, param.mods) + })(typeCompleter(param)) param.symbol } else param.symbol vparamss.map(_.map(enterValueParam)) @@ -477,7 +524,7 @@ trait Namers { self: Analyzer => def enterSelf(self: ValDef) { if (!self.tpt.isEmpty) { clazz.typeOfThis = selfTypeCompleter(self.tpt) - self.symbol = clazz.thisSym + self.symbol = clazz.thisSym.setPos(self.pos) } else { self.tpt.tpe = NoType if (self.name != nme.WILDCARD) { @@ -489,13 +536,13 @@ trait Namers { self: Analyzer => } if (self.name != nme.WILDCARD) { self.symbol.name = self.name - context.scope enter self.symbol + self.symbol = context.scope enter self.symbol } } val parents = typer.parentTypes(templ) map checkParent enterSelf(templ.self) - val decls = newDecls(templ, clazz) - new Namer(context.make(templ, clazz, decls)).enterSyms(templ.body) + val decls = newDecls(clazz) + newNamer(context.make(templ, clazz, decls)).enterSyms(templ.body) ClassInfoType(parents, decls, clazz) } @@ -507,7 +554,14 @@ trait Namers { self: Analyzer => val meth = context.owner val tparamSyms = typer.reenterTypeParams(tparams) - var vparamSymss = enterValueParams(meth, vparamss) + var vparamSymss = + if (inIDE && meth.isPrimaryConstructor) { + // @S: because they have already been entered this way.... + assert(true) + enterValueParams(meth.owner.owner, vparamss) + } else { + enterValueParams(meth, vparamss) + } if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) tpt.tpe = context.enclClass.owner.tpe if (onlyPresentation) @@ -700,7 +754,7 @@ trait Namers { self: Analyzer => val ainfos = for { annot <- defn.mods.annotations val ainfo = typer.typedAnnotation(annot) - if !ainfo.atp.isError + if !ainfo.atp.isError && annot != null } yield ainfo if (!ainfos.isEmpty) { val annotated = if (sym.isModule) sym.moduleClass else sym @@ -712,17 +766,17 @@ trait Namers { self: Analyzer => try { tree match { case ClassDef(_, _, tparams, impl) => - new Namer(makeNewScope(context, tree, sym)).classSig(tparams, impl) + newNamer(context.makeNewScope(tree, sym)).classSig(tparams, impl) case ModuleDef(_, _, impl) => val clazz = sym.moduleClass - clazz.setInfo(new Namer(makeNewScope(context, tree, clazz)).templateSig(impl)) + clazz.setInfo(newNamer(context.makeNewScope(tree, clazz)).templateSig(impl)) //clazz.typeOfThis = singleType(sym.owner.thisType, sym); clazz.tpe; case DefDef(_, _, tparams, vparamss, tpt, rhs) => val result = - new Namer(makeNewScope(context, tree, sym)).methodSig(tparams, vparamss, tpt, rhs); + newNamer(context.makeNewScope(tree, sym)).methodSig(tparams, vparamss, tpt, rhs); checkContractive(sym, result) case vdef @ ValDef(mods, _, tpt, rhs) => @@ -741,7 +795,7 @@ trait Namers { self: Analyzer => } else typer1.typedType(tpt).tpe case TypeDef(_, _, tparams, rhs) => - new Namer(makeNewScope(context, tree, sym)).typeDefSig(sym, tparams, rhs) //@M! + newNamer(context.makeNewScope(tree, sym)).typeDefSig(sym, tparams, rhs) //@M! case Import(expr, selectors) => val expr1 = typer.typedQualifier(expr) @@ -813,7 +867,7 @@ trait Namers { self: Analyzer => } if (sym.hasFlag(IMPLICIT) && !sym.isTerm) context.error(sym.pos, "`implicit' modifier can be used only for values, variables and methods") - if (sym.hasFlag(IMPLICIT) && sym.owner.isPackageClass) + if (sym.hasFlag(IMPLICIT) && sym.owner.isPackageClass && !inIDE) context.error(sym.pos, "`implicit' modifier cannot be used for top-level objects") if (sym.hasFlag(ABSTRACT) && !sym.isClass) context.error(sym.pos, "`abstract' modifier can be used only for classes; " + diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index aa5a2909e1..7323529d94 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -84,7 +84,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } } - override def transform(tree: Tree): Tree = tree match { + override def transform(tree: Tree): Tree = try { tree match { case ClassDef(_, _, _, _) => checkCompanionNameClashes(tree.symbol) val decls = tree.symbol.info.decls @@ -181,6 +181,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT super.transform(tree) case Apply(fn, args) => + assert(fn.tpe != null) copy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.paramTypes)) case Function(vparams, body) => withInvalidOwner { @@ -188,6 +189,12 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } case _ => super.transform(tree) + }} catch { + case ex : AssertionError => + if (tree.symbol != null && tree.symbol != NoSymbol) + Console.println("TRANSFORM: " + tree.symbol.sourceFile) + Console.println("TREE: " + tree) + throw ex } override def atOwner[A](owner: Symbol)(trans: => A): A = { diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 8fb892670b..d9ee9071cd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -29,7 +29,11 @@ import scala.collection.mutable.ListBuffer trait SyntheticMethods { self: Analyzer => import global._ // the global environment import definitions._ // standard classes and methods - import typer.{typed} // methods to type trees + //import global.typer.{typed} // methods to type trees + // @S: type hack: by default, we are used from global.analyzer context + // so this cast won't fail. If we aren't in global.analyzer, we have + // to override this method anyways. + protected def typer : Typer = global.typer.asInstanceOf[Typer] /** * @param templ ... @@ -42,15 +46,15 @@ trait SyntheticMethods { self: Analyzer => val localContext = if (reporter.hasErrors) context.makeSilent(false) else context val localTyper = newTyper(localContext) - def hasImplementation(name: Name): Boolean = { + def hasImplementation(name: Name): Boolean = if (inIDE) true else { val sym = clazz.info.nonPrivateMember(name) sym.isTerm && !(sym hasFlag DEFERRED) } - def hasOverridingImplementation(meth: Symbol): Boolean = { + def hasOverridingImplementation(meth: Symbol): Boolean = if (inIDE) true else { val sym = clazz.info.nonPrivateMember(meth.name) sym.alternatives exists { sym => - sym != meth && !(sym hasFlag DEFERRED) && + sym != meth && !(sym hasFlag DEFERRED) && !(sym hasFlag SYNTHETIC) && (clazz.thisType.memberType(sym) matches clazz.thisType.memberType(meth)) } } @@ -59,8 +63,11 @@ trait SyntheticMethods { self: Analyzer => newSyntheticMethod(name, flags | OVERRIDE, tpe) def newSyntheticMethod(name: Name, flags: Int, tpe: Type) = { - val method = clazz.newMethod(clazz.pos, name) setFlag (flags) setInfo tpe - clazz.info.decls.enter(method) + var method = clazz.newMethod(clazz.pos, name) setFlag ({ + if (inIDE) flags | SYNTHETIC + else flags + }) setInfo tpe + method = clazz.info.decls.enter(method).asInstanceOf[TermSymbol] method } @@ -72,18 +79,18 @@ trait SyntheticMethods { self: Analyzer => */ def productPrefixMethod: Tree = { val method = syntheticMethod(nme.productPrefix, FINAL, PolyType(List(), StringClass.tpe)) - typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) + typer.typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) } def productArityMethod(nargs:Int ): Tree = { val method = syntheticMethod(nme.productArity, FINAL, PolyType(List(), IntClass.tpe)) - typed(DefDef(method, vparamss => Literal(Constant(nargs)))) + typer.typed(DefDef(method, vparamss => Literal(Constant(nargs)))) } def productElementMethod(accs: List[Symbol]): Tree = { //val retTpe = lub(accs map (_.tpe.resultType)) val method = syntheticMethod(nme.productElement, FINAL, MethodType(List(IntClass.tpe), AnyClass.tpe/*retTpe*/)) - typed(DefDef(method, vparamss => Match(Ident(vparamss.head.head), { + typer.typed(DefDef(method, vparamss => Match(Ident(vparamss.head.head), { (for ((sym,i) <- accs.zipWithIndex) yield { CaseDef(Literal(Constant(i)),EmptyTree, Ident(sym)) }):::List(CaseDef(Ident(nme.WILDCARD), EmptyTree, @@ -95,12 +102,12 @@ trait SyntheticMethods { self: Analyzer => def moduleToStringMethod: Tree = { val method = syntheticMethod(nme.toString_, FINAL, MethodType(List(), StringClass.tpe)) - typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) + typer.typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) } def tagMethod: Tree = { val method = syntheticMethod(nme.tag, FINAL, MethodType(List(), IntClass.tpe)) - typed(DefDef(method, vparamss => Literal(Constant(clazz.tag)))) + typer.typed(DefDef(method, vparamss => Literal(Constant(clazz.tag)))) } def forwardingMethod(name: Name): Tree = { @@ -110,7 +117,7 @@ trait SyntheticMethods { self: Analyzer => else target.tpe.paramTypes.tail val method = syntheticMethod( name, 0, MethodType(paramtypes, target.tpe.resultType)) - typed(DefDef(method, vparamss => + typer.typed(DefDef(method, vparamss => Apply(gen.mkAttributedRef(target), This(clazz) :: (vparamss.head map Ident)))) } @@ -148,7 +155,7 @@ trait SyntheticMethods { self: Analyzer => val (pat, guard) = { val guards = new ListBuffer[Tree] val params = for ((acc, cpt) <- clazz.caseFieldAccessors zip constrParamTypes) yield { - val name = context.unit.fresh.newName(acc.name+"$") + val name = context.unit.fresh.newName(clazz.pos, acc.name+"$") val isVarArg = cpt.typeSymbol == RepeatedParamClass guards += Apply( Select( @@ -185,16 +192,16 @@ trait SyntheticMethods { self: Analyzer => // but then it is renamed !!! val method = newSyntheticMethod(nme.readResolve, PROTECTED, MethodType(List(), ObjectClass.tpe)) - typed(DefDef(method, vparamss => gen.mkAttributedRef(clazz.sourceModule))) + typer.typed(DefDef(method, vparamss => gen.mkAttributedRef(clazz.sourceModule))) } def newAccessorMethod(tree: Tree): Tree = tree match { case DefDef(_, _, _, _, _, rhs) => - val newAcc = tree.symbol.cloneSymbol - newAcc.name = context.unit.fresh.newName(tree.symbol.name + "$") + var newAcc = tree.symbol.cloneSymbol + newAcc.name = context.unit.fresh.newName(tree.symbol.pos, tree.symbol.name + "$") newAcc.setFlag(SYNTHETIC).resetFlag(ACCESSOR | PARAMACCESSOR | PRIVATE) - newAcc.owner.info.decls enter newAcc - val result = typed(DefDef(newAcc, vparamss => rhs.duplicate)) + newAcc = newAcc.owner.info.decls enter newAcc + val result = typer.typed(DefDef(newAcc, vparamss => rhs.duplicate)) log("new accessor method " + result) result } @@ -226,7 +233,7 @@ trait SyntheticMethods { self: Analyzer => def addBeanGetterMethod(sym: Symbol) = { val getter = beanSetterOrGetter(sym) if (getter != NoSymbol) - ts += typed(DefDef( + ts += typer.typed(DefDef( getter, vparamss => if (sym hasFlag DEFERRED) EmptyTree else gen.mkAttributedRef(sym))) } @@ -234,7 +241,7 @@ trait SyntheticMethods { self: Analyzer => def addBeanSetterMethod(sym: Symbol) = { val setter = beanSetterOrGetter(sym) if (setter != NoSymbol) - ts += typed(DefDef( + ts += typer.typed(DefDef( setter, vparamss => if (sym hasFlag DEFERRED) EmptyTree @@ -257,7 +264,7 @@ trait SyntheticMethods { self: Analyzer => } } - if (clazz.info.nonPrivateDecl(nme.tag) == NoSymbol) ts += tagMethod + if (!inIDE && clazz.info.nonPrivateDecl(nme.tag) == NoSymbol) ts += tagMethod if (clazz.isModuleClass) { if (!hasOverridingImplementation(Object_toString)) ts += moduleToStringMethod } else { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index cd852c8b50..1ef6b935e7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -44,7 +44,6 @@ trait Typers { self: Analyzer => superDefs.clear } - def newTyper(context: Context): Typer = new Typer(context) object UnTyper extends Traverser { override def traverse(tree: Tree) = { @@ -53,12 +52,20 @@ trait Typers { self: Analyzer => super.traverse(tree) } } - def makeNewScope(txt: Context, tree: Tree, sym: Symbol) = - txt.makeNewScope(tree, sym) + // IDE hooks + def newTyper(context: Context): Typer = new NormalTyper(context) + private class NormalTyper(context : Context) extends Typer(context) + def scopeFor(tree : Tree) : Scope = newScope + def newLocalDummy(clazz : Symbol, pos : Position) = clazz.newLocalDummy(pos) + def recycle(sym : Symbol) : Symbol = sym + // hooks for auto completion + def compare(sym : Symbol, name : Name) = sym.name == name + def verifyAndPrioritize[T](g : Symbol => Symbol)(pt : Type)(f : => T) = f + def trackSetInfo[T <: Symbol](sym : T)(info : Type) : T = { + sym.setInfo(info) + sym + } - def newDecls(tree: CompoundTypeTree) = newScope - def newDecls(tree: Template, clazz: Symbol) = newScope - def newTemplateScope(impl: Template, clazz: Symbol) = newScope // Mode constants @@ -132,7 +139,7 @@ trait Typers { self: Analyzer => private def argMode(fun: Tree, mode: Int) = if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode else mode - class Typer(context0: Context) { + abstract class Typer(context0: Context) { import context0.unit val infer = new Inferencer(context0) { @@ -177,9 +184,10 @@ trait Typers { self: Analyzer => */ private def inferView(pos: Position, from: Type, name: Name, tp: Type, reportAmbiguous: Boolean): Tree = { val to = refinedType(List(WildcardType), NoSymbol) - val psym = (if (name.isTypeName) to.typeSymbol.newAbstractType(pos, name) - else to.typeSymbol.newValue(pos, name)) setInfo tp - to.decls.enter(psym) + var psym = (if (name.isTypeName) to.typeSymbol.newAbstractType(pos, name) + else to.typeSymbol.newValue(pos, name)) + psym = to.decls enter psym + psym setInfo tp inferView(pos, from, to, reportAmbiguous) } @@ -188,7 +196,7 @@ trait Typers { self: Analyzer => private var namerCache: Namer = null def namer = { if ((namerCache eq null) || namerCache.context != context) - namerCache = new Namer(context) + namerCache = newNamer(context) namerCache } @@ -346,7 +354,7 @@ trait Typers { self: Analyzer => this.scope = scope hiddenSymbols = List() val tp1 = apply(tree.tpe) - if (hiddenSymbols.isEmpty) tree setType tp1 + if (hiddenSymbols.isEmpty || inIDE) tree setType tp1 // @S: because arguments of classes are owned by the classes' owner else if (hiddenSymbols exists (_.isErroneous)) setError(tree) else if (isFullyDefined(pt)) tree setType pt //todo: eliminate else if (tp1.typeSymbol.isAnonymousClass) // todo: eliminate @@ -412,7 +420,10 @@ trait Typers { self: Analyzer => def reenterTypeParams(tparams: List[TypeDef]): List[Symbol] = for (tparam <- tparams) yield { - context.scope enter tparam.symbol + val rawInfo = tparam.symbol.rawInfo + tparam.symbol = context.scope enter tparam.symbol + // hack, because the skolems are reused. + if (inIDE) tparam.symbol.setInfo(rawInfo) tparam.symbol.deSkolemize } @@ -446,7 +457,7 @@ trait Typers { self: Analyzer => */ def labelTyper(ldef: LabelDef): Typer = if (ldef.symbol == NoSymbol) { // labeldef is part of template - val typer1 = newTyper(makeNewScope(context, ldef, context.owner)) + val typer1 = newTyper(context.makeNewScope(ldef, context.owner)) typer1.enterLabelDef(ldef) typer1 } else this @@ -597,7 +608,7 @@ trait Typers { self: Analyzer => * If all this fails, error */ protected def adapt(tree: Tree, mode: int, pt: Type): Tree = tree.tpe match { - case ct @ ConstantType(value) if ((mode & TYPEmode) == 0 && (ct <:< pt)) => // (0) + case ct @ ConstantType(value) if ((mode & TYPEmode) == 0 && (ct <:< pt) && !inIDE) => // (0) copy.Literal(tree, value) case OverloadedType(pre, alts) if ((mode & FUNmode) == 0) => // (1) inferExprAlternative(tree, pt) @@ -641,7 +652,7 @@ trait Typers { self: Analyzer => (pt <:< functionType(mt.paramTypes map (t => WildcardType), WildcardType))) { // (4.2) if (settings.debug.value) log("eta-expanding "+tree+":"+tree.tpe+" to "+pt) checkParamsConvertible(tree.pos, tree.tpe) - typed(etaExpand(tree), mode, pt) + typed(etaExpand(context.unit, tree), mode, pt) } else if (!meth.isConstructor && mt.paramTypes.isEmpty) { // (4.3) adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt) } else if (context.implicitsEnabled) { @@ -781,9 +792,6 @@ trait Typers { self: Analyzer => } } } -// Console.println("adapt "+tree+":"+tree.tpe+", mode = "+mode+", pt = "+pt) -// adapt(tree, mode, pt) -// } /** * @param tree ... @@ -820,7 +828,8 @@ trait Typers { self: Analyzer => if (member(qual, name) != NoSymbol) qual else adaptToMember(qual, name, WildcardType) - private def typePrimaryConstrBody(cbody: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]]): Tree = { + private def typePrimaryConstrBody(clazz : Symbol, cbody: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]]): Tree = { + // XXX: see about using the class's symbol.... enclTparams foreach (sym => context.scope.enter(sym)) namer.enterValueParams(context.owner, vparamss) typed(cbody) @@ -879,8 +888,8 @@ trait Typers { self: Analyzer => val outercontext = context.outer val cbody2 = - newTyper(makeNewScope(outercontext, constr, outercontext.owner)) - .typePrimaryConstrBody( + newTyper(outercontext.makeNewScope(constr, outercontext.owner)) + .typePrimaryConstrBody(clazz, cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate))) scall match { @@ -952,7 +961,8 @@ trait Typers { self: Analyzer => //Console.println(context.owner);//DEBUG //Console.println(context.owner.unsafeTypeParams);//DEBUG //Console.println(List.fromArray(context.owner.info.closure));//DEBUG - error(parent.pos, "illegal inheritance;\n self-type "+ + // disable in IDE, don't know how else to avoid it on refresh + if (!inIDE) error(parent.pos, "illegal inheritance;\n self-type "+ selfType+" does not conform to "+parent + "'s selftype "+parent.tpe.typeOfThis) if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis) @@ -992,10 +1002,15 @@ trait Typers { self: Analyzer => def typedClassDef(cdef: ClassDef): Tree = { // attributes(cdef) val typedMods = typedModifiers(cdef.mods) - val clazz = cdef.symbol + val clazz = cdef.symbol; + if (inIDE && clazz == NoSymbol) { + assert(true) + throw new TypeError("type signature typing failed") + } + assert(clazz != NoSymbol) reenterTypeParams(cdef.tparams) val tparams1 = List.mapConserve(cdef.tparams)(typedTypeDef) - val impl1 = newTyper(context.make(cdef.impl, clazz, newTemplateScope(cdef.impl, clazz))) + val impl1 = newTyper(context.make(cdef.impl, clazz, scopeFor(cdef.impl))) .typedTemplate(cdef.impl, parentTypes(cdef.impl)) val impl2 = addSyntheticMethods(impl1, clazz, context) copy.ClassDef(cdef, typedMods, cdef.name, tparams1, impl2) @@ -1011,7 +1026,9 @@ trait Typers { self: Analyzer => // attributes(mdef) val typedMods = typedModifiers(mdef.mods) val clazz = mdef.symbol.moduleClass - val impl1 = newTyper(context.make(mdef.impl, clazz, newTemplateScope(mdef.impl, clazz))) + if (inIDE && clazz == NoSymbol) throw new TypeError("bad signature") + assert(clazz != NoSymbol) + val impl1 = newTyper(context.make(mdef.impl, clazz, scopeFor(mdef.impl))) .typedTemplate(mdef.impl, parentTypes(mdef.impl)) val impl2 = addSyntheticMethods(impl1, clazz, context) @@ -1029,7 +1046,10 @@ trait Typers { self: Analyzer => && !stat.symbol.hasFlag(LAZY) => val vdef = copy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs) val value = vdef.symbol - val getter = if ((mods hasFlag DEFERRED) || inIDE) value else value.getter(value.owner) + val getter = if ((mods hasFlag DEFERRED)) value else value.getter(value.owner) + // XXX: + if (inIDE && getter == NoSymbol) + return Nil assert(getter != NoSymbol, stat) if (getter hasFlag OVERLOADED) error(getter.pos, getter+" is defined twice") @@ -1080,7 +1100,7 @@ trait Typers { self: Analyzer => protected def enterSym(txt: Context, tree: Tree): Context = if (txt eq context) namer.enterSym(tree) - else new Namer(txt).enterSym(tree) + else newNamer(txt).enterSym(tree) /** * @param templ ... @@ -1090,7 +1110,7 @@ trait Typers { self: Analyzer => def typedTemplate(templ: Template, parents1: List[Tree]): Template = { val clazz = context.owner if (templ.symbol == NoSymbol) - templ setSymbol clazz.newLocalDummy(templ.pos) + templ setSymbol newLocalDummy(clazz, templ.pos) val self1 = templ.self match { case vd @ ValDef(mods, name, tpt, EmptyTree) => val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(tpt)) @@ -1102,9 +1122,12 @@ trait Typers { self: Analyzer => intersectionType(clazz.info.parents, clazz.owner) else clazz.typeOfThis // the following is necessary for templates generated later - enterSyms(context.outer.make(templ, clazz, clazz.info.decls), templ.body) + assert(clazz.info.decls != EmptyScope) + // XXX: let namer in typeSig be definitive, duplicate to ensure typer context doesn't stick. + val templBody = if (inIDE) templ.body.map(_.duplicate : Tree) else templ.body + enterSyms(context.outer.make(templ, clazz, clazz.info.decls), templBody) validateParentClasses(parents1, selfType) - if (!phase.erasedTypes) + if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType]) val body = if (phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) @@ -1131,7 +1154,10 @@ trait Typers { self: Analyzer => val typer1 = constrTyperIf(sym.hasFlag(PARAM) && sym.owner.isConstructor) val typedMods = typedModifiers(vdef.mods) - val tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt)) + var tpt1 = checkNoEscaping.privates(sym, typer1.typedType({ + if (inIDE) vdef.tpt.duplicate // avoids wrong context sticking + else vdef.tpt + })) checkNonCyclic(vdef, tpt1) val rhs1 = if (vdef.rhs.isEmpty) { @@ -1139,7 +1165,9 @@ trait Typers { self: Analyzer => error(vdef.pos, "local variables must be initialized") vdef.rhs } else { - newTyper(typer1.context.make(vdef, sym)).transformedOrTyped(vdef.rhs, tpt1.tpe) + //assert(vdef.rhs.tpe == null) + val rhs = if (inIDE && vdef.rhs.tpe != null) vdef.rhs.duplicate else vdef.rhs + newTyper(typer1.context.make(vdef, sym)).transformedOrTyped(rhs, tpt1.tpe) } copy.ValDef(vdef, typedMods, vdef.name, tpt1, checkDead(rhs1)) setType NoType } @@ -1155,11 +1183,14 @@ trait Typers { self: Analyzer => def decompose(call: Tree): (Tree, List[Tree]) = call match { case Apply(fn, args) => val (superConstr, args1) = decompose(fn) - val formals = fn.tpe.paramTypes + val formals = (if (fn.tpe == null && inIDE) ErrorType else fn.tpe).paramTypes val args2 = if (formals.isEmpty || formals.last.typeSymbol != RepeatedParamClass) args else args.take(formals.length - 1) ::: List(EmptyTree) - if (args2.length != formals.length) - assert(false, "mismatch " + clazz + " " + formals + " " + args2);//debug + if (args2.length != formals.length) { + if (!inIDE) + assert(false, "mismatch " + clazz + " " + formals + " " + args2);//debug + else error(call.pos, "XXX: mismatch " + clazz + " " + formals + " " + args2) + } (superConstr, args1 ::: args2) case Block(stats, expr) if !stats.isEmpty => decompose(stats.last) @@ -1198,6 +1229,12 @@ trait Typers { self: Analyzer => } () } + } else if (inIDE) { // XXX: maybe add later + Console.println("" + superClazz + ":" + + superClazz.info.decls.toList.filter(_.hasFlag(PARAMACCESSOR))) + error(rhs.pos, "mismatch: " + superParamAccessors + + ";" + rhs + ";" + superClazz.info.decls)//debug + return } } } @@ -1215,6 +1252,7 @@ trait Typers { self: Analyzer => */ def typedDefDef(ddef: DefDef): DefDef = { val meth = ddef.symbol + if (inIDE && meth == NoSymbol) throw new TypeError("bad signature") reenterTypeParams(ddef.tparams) reenterValueParams(ddef.vparamss) val tparams1 = List.mapConserve(ddef.tparams)(typedTypeDef) @@ -1240,7 +1278,8 @@ trait Typers { self: Analyzer => error(ddef.pos, "constructor definition not allowed here") typed(ddef.rhs) } else { - transformedOrTyped(ddef.rhs, tpt1.tpe) + if (inIDE && ddef.rhs == EmptyTree) EmptyTree + else transformedOrTyped(ddef.rhs, tpt1.tpe) } if (meth.isPrimaryConstructor && meth.isClassConstructor && phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) @@ -1310,8 +1349,7 @@ trait Typers { self: Analyzer => if (stat.isDef) context.scope.enter(stat.symbol) } } - if (!inIDE) - namer.enterSyms(block.stats) + namer.enterSyms(block.stats) block.stats foreach enterLabelDef val stats1 = typedStats(block.stats, context.owner) val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt) @@ -1359,7 +1397,7 @@ trait Typers { self: Analyzer => def typedCases(tree: Tree, cases: List[CaseDef], pattp0: Type, pt: Type): List[CaseDef] = { var pattp = pattp0 List.mapConserve(cases) ( cdef => - newTyper(makeNewScope(context, cdef, context.owner)).typedCase(cdef, pattp, pt)) + newTyper(context.makeNewScope(cdef, context.owner)).typedCase(cdef, pattp, pt)) /* not yet! cdef.pat match { case Literal(Constant(null)) => @@ -1410,8 +1448,6 @@ trait Typers { self: Analyzer => vparam.symbol } // XXX: here to for IDE hooks. - if (inIDE) // HACK to process arguments types in IDE. - typedFunctionIDE(fun, context); val vparams = List.mapConserve(fun.vparams)(typedValDef) // for (val vparam <- vparams) { // checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); () @@ -1430,8 +1466,7 @@ trait Typers { self: Analyzer => } def typedRefinement(stats: List[Tree]): List[Tree] = { - if (!inIDE) - namer.enterSyms(stats) + namer.enterSyms(stats) val stats1 = typedStats(stats, NoSymbol) for (stat <- stats1 if stat.isDef) { val member = stat.symbol @@ -1457,14 +1492,21 @@ trait Typers { self: Analyzer => context = context.makeNewImport(imp0) imp0.symbol.initialize } - EmptyTree + if ((imp0 ne null) && inIDE) { + imp0.symbol.info match { + case ImportType(exr) => + imp0.expr.tpe = exr.tpe + case _ => + } + imp0 + } else EmptyTree case _ => val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) this else newTyper(context.make(stat, exprOwner)) val result = checkDead(localTyper.typed(stat)) if (treeInfo.isSelfOrSuperConstrCall(result)) { context.inConstructorSuffix = true - if (treeInfo.isSelfConstrCall(result) && result.symbol.pos.offset.get(0) >= exprOwner.enclMethod.pos.offset.get(0)) + if (!inIDE && treeInfo.isSelfConstrCall(result) && result.symbol.pos.offset.get(0) >= exprOwner.enclMethod.pos.offset.get(0)) error(stat.pos, "called constructor's definition must precede calling constructor's definition") } result @@ -1482,7 +1524,7 @@ trait Typers { self: Analyzer => while ((e1 ne null) && e1.owner == scope) { if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) && (e.sym.isType || inBlock || (e.sym.tpe matches e1.sym.tpe))) - if (!e.sym.isErroneous && !e1.sym.isErroneous) + if (!e.sym.isErroneous && !e1.sym.isErroneous && !inIDE) error(e.sym.pos, e1.sym+" is defined twice"+ {if(!settings.debug.value) "" else " in "+unit.toString}); e1 = scope.lookupNextEntry(e1); @@ -1593,7 +1635,7 @@ trait Typers { self: Analyzer => } } - if (fun.symbol == List_apply && args.isEmpty) { + if (!inIDE && fun.symbol == List_apply && args.isEmpty) { atPos(tree.pos) { gen.mkNil setType restpe } } else constfold(copy.Apply(tree, fun, args2).setType(ifPatternSkipFormals(restpe))) @@ -1618,8 +1660,9 @@ trait Typers { self: Analyzer => else { if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args2.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info));//debug val undetparams = inferMethodInstance(fun, tparams, args2, pt) - val result = doTypedApply(tree, fun, args2, mode, pt) - context.undetparams = undetparams + val result = if (!inIDE) doTypedApply(tree, fun, args2, mode, pt) + else doTypedApply(tree.duplicate,fun.duplicate,args2.map(_.duplicate),mode,pt) + context.undetparams = undetparams result } } @@ -1637,6 +1680,7 @@ trait Typers { self: Analyzer => assert(unapp.exists, tree) val unappType = otpe.memberType(unapp) val argDummyType = pt // was unappArg + // @S: do we need to memoize this? val argDummy = context.owner.newValue(fun.pos, nme.SELECTOR_DUMMY) .setFlag(SYNTHETIC) .setInfo(argDummyType) @@ -1659,7 +1703,7 @@ trait Typers { self: Analyzer => val (unappFormal, freeVars) = freshArgType(unappType) val context1 = context.makeNewScope(context.tree, context.owner) freeVars foreach(sym => context1.scope.enter(sym)) - val typer1 = new Typer(context1) + val typer1 = newTyper(context1) arg.tpe = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe) //todo: replace arg with arg.asInstanceOf[inferTypedPattern(unappFormal, arg.tpe)] instead. argDummy.setInfo(arg.tpe) // bq: this line fixed #1281. w.r.t. comment ^^^, maybe good enough? @@ -1833,10 +1877,10 @@ trait Typers { self: Analyzer => val typeParams: List[Symbol] = rawSyms map { sym => val name = if (sym.isType) sym.name else newTypeName(sym.name+".type") val bound = existentialBound(sym) - val quantified: Symbol = sym.owner.newAbstractType(sym.pos, name) - quantified setFlag EXISTENTIAL setInfo bound.cloneInfo(quantified) + val quantified: Symbol = recycle(sym.owner.newAbstractType(sym.pos, name)) + trackSetInfo(quantified setFlag EXISTENTIAL)(bound.cloneInfo(quantified)) } - val typeParamTypes = typeParams map (_.tpe) + val typeParamTypes = typeParams map (_.tpe) // don't trackSetInfo here, since type already set! for (tparam <- typeParams) tparam.setInfo(tparam.info.subst(rawSyms, typeParamTypes)) (typeParams, tp.subst(rawSyms, typeParamTypes)) } @@ -1916,10 +1960,9 @@ trait Typers { self: Analyzer => case t => t } - val local = sym.owner.newAbstractType( - sym.pos, unit.fresh.newName(sym.name.toString)) - .setFlag(sym.flags) - .setInfo(bound) + val local = trackSetInfo(recycle(sym.owner.newAbstractType( + sym.pos, unit.fresh.newName(sym.pos, sym.name.toString)) + .setFlag(sym.flags)))(bound) localInstances += (inst -> local) addLocals(bound) } @@ -2015,8 +2058,10 @@ trait Typers { self: Analyzer => else context.owner.newAbstractType(tree.pos, name) setInfo mkTypeBounds(AllClass.tpe, AnyClass.tpe) - if (vble.name == nme.WILDCARD.toTypeName) context.scope.enter(vble) - else namer.enterInScope(vble) + val rawInfo = vble.rawInfo + vble = if (vble.name == nme.WILDCARD.toTypeName) context.scope.enter(vble) + else namer.enterInScope(vble) + trackSetInfo(vble)(rawInfo) // vble could have been recycled, detect changes in type tree setSymbol vble setType vble.tpe } else { if (vble == NoSymbol) @@ -2031,10 +2076,10 @@ trait Typers { self: Analyzer => */ if ((mode & ALTmode) != 0) error(tree.pos, "illegal variable in pattern alternative") - namer.enterInScope(vble) + vble = namer.enterInScope(vble) } val body1 = typed(body, mode, pt) - vble.setInfo( + trackSetInfo(vble)( if (treeInfo.isSequenceValued(body)) seqType(body1.tpe) else body1.tpe) copy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // buraq, was: pt @@ -2100,12 +2145,17 @@ trait Typers { self: Analyzer => errorTree(tree, "return outside method definition") } else { val DefDef(_, _, _, _, restpt, _) = enclMethod.tree - if (restpt.tpe eq null) { - errorTree(tree, "method " + enclMethod.owner + + var restpt0 = restpt + if (inIDE && (restpt0.tpe eq null)) { + assert(true) + restpt0 = typed(restpt0, TYPEmode, WildcardType) + } + if (restpt0.tpe eq null) { + errorTree(tree, "" + enclMethod.owner + " has return statement; needs result type") } else { context.enclMethod.returnsSeen = true - val expr1: Tree = typed(expr, restpt.tpe) + val expr1: Tree = typed(expr, restpt0.tpe) copy.Return(tree, checkDead(expr1)) setSymbol enclMethod.owner setType AllClass.tpe } } @@ -2372,7 +2422,7 @@ trait Typers { self: Analyzer => if ((mode & SUPERCONSTRmode) != 0) clazz.info.parents.head else intersectionType(clazz.info.parents) else { - val ps = clazz.info.parents filter (p => p.typeSymbol.name == mix) + val ps = clazz.info.parents filter (p => compare(p.typeSymbol, mix)) if (ps.isEmpty) { if (settings.debug.value) Console.println(clazz.info.parents map (_.typeSymbol.name))//debug @@ -2429,7 +2479,8 @@ trait Typers { self: Analyzer => } tree.symbol } else { - member(qual, name) + if (!inIDE) member(qual, name) + else verifyAndPrioritize(_ filter (alt => context.isAccessible(alt, qual.tpe, qual.isInstanceOf[Super])))(pt)(member(qual,name)) } if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & EXPRmode) != 0) { val qual1 = adaptToName(qual, name) @@ -2510,6 +2561,7 @@ trait Typers { self: Analyzer => ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || !sym.isSourceMethod || sym.isCaseFactory) + if (defSym == NoSymbol) { var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope @@ -2520,22 +2572,23 @@ trait Typers { self: Analyzer => while (defSym == NoSymbol && cx != NoContext) { pre = cx.enclClass.prefix - defEntry = cx.scope.lookupEntry(name) - if (inIDE && (defEntry ne null) && defEntry.sym.exists) { - val sym = defEntry.sym - val namePos : Position = tree.pos - val symPos : Position = sym.pos - if (namePos.offset.get < symPos.offset.get) defEntry = null - } + defEntry = if (!inIDE) cx.scope.lookupEntry(name) + else verifyAndPrioritize(sym => sym)(pt)(cx.scope.lookupEntry(name)) if ((defEntry ne null) && qualifies(defEntry.sym)) { defSym = defEntry.sym - } else if (inIDE) { - if (cx.outer == cx.enclClass) { - cx = cx.enclClass - defSym = pre.member(name) filter ( - sym => sym.exists && context.isAccessible(sym, pre, false)) + } else if (inIDE) { // IDE: cannot rely on linked scopes. + if (cx.outer.owner eq cx.enclClass.owner) { + //cx = cx.outer + defSym = + verifyAndPrioritize{ // enables filtering of auto completion + _ filter (sym => qualifies(sym) && context.isAccessible(sym, pre, false)) + }(pt)(pre.member(name) filter ( + sym => qualifies(sym) && context.isAccessible(sym, pre, false))) } - if (defSym == NoSymbol) cx = cx.outer + val oldScope = cx.scope + cx = cx.outer + while (cx.scope == oldScope && !(cx.outer.owner eq cx.enclClass.owner)) // can't skip + cx = cx.outer } else { cx = cx.enclClass defSym = pre.member(name) filter ( @@ -2562,7 +2615,7 @@ trait Typers { self: Analyzer => // imported symbols take precedence over package-owned symbols in different // compilation units. Defined symbols take precedence over errenous imports. if (defSym.owner.isPackageClass && - (!currentRun.compiles(defSym) || + ((!inIDE && !currentRun.compiles(defSym)) || (context.unit ne null) && defSym.sourceFile != context.unit.source.file)) defSym = NoSymbol else if (impSym.isError) @@ -2614,9 +2667,14 @@ trait Typers { self: Analyzer => } } if (defSym.owner.isPackageClass) pre = defSym.owner.thisType - if (defSym.isThisSym) typed1(This(defSym.owner) setPos tree.pos, mode, pt) + if (defSym.isThisSym) { + val tree1 = typed1(This(defSym.owner) setPos tree.pos, mode, pt) + if (inIDE) { + Ident(defSym.name) setType tree1.tpe setSymbol defSym setPos tree.pos + } else tree1 + } else { - val tree1 = if (qual == EmptyTree) tree + var tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(qual, name)) // atPos necessary because qualifier might come from startContext stabilize(checkAccessible(tree1, defSym, pre, qual), pre, mode, pt) @@ -2627,7 +2685,7 @@ trait Typers { self: Analyzer => val parents1 = List.mapConserve(templ.parents)(typedType) if (parents1 exists (_.tpe.isError)) tree setType ErrorType else { - val decls = newDecls(tree.asInstanceOf[CompoundTypeTree]) + val decls = scopeFor(tree) val self = refinedType(parents1 map (_.tpe), context.enclClass.owner, decls) newTyper(context.make(templ, self.typeSymbol, decls)).typedRefinement(templ.body) tree setType self @@ -2636,6 +2694,8 @@ trait Typers { self: Analyzer => def typedAppliedTypeTree(tpt: Tree, args: List[Tree]) = { val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType) + // @S: shouldn't be necessary now, fixed a problem with SimpleTypeProxy not relaying typeParams calls. + // if (inIDE) tpt1.symbol.info // @S: seems like typeParams call doesn't force completion of symbol type in IDE. val tparams = tpt1.symbol.typeParams if (tpt1.tpe.isError) { @@ -2654,7 +2714,7 @@ trait Typers { self: Analyzer => // note: can't use args1 in selector, because Bind's got replaced case Bind(_, _) => if (arg.symbol.isAbstractType) - arg.symbol setInfo + arg.symbol setInfo // XXX, feedback. don't trackSymInfo here! TypeBounds(lub(List(arg.symbol.info.bounds.lo, tparam.info.bounds.lo)), glb(List(arg.symbol.info.bounds.hi, tparam.info.bounds.hi))) case _ => @@ -2675,24 +2735,25 @@ trait Typers { self: Analyzer => //if (settings.debug.value && tree.isDef) log("typing definition of "+sym);//DEBUG tree match { case PackageDef(name, stats) => + assert(sym.moduleClass ne NoSymbol) val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls)) .typedStats(stats, NoSymbol) copy.PackageDef(tree, name, stats1) setType NoType case tree @ ClassDef(_, _, _, _) => - newTyper(makeNewScope(context, tree, sym)).typedClassDef(tree) + newTyper(context.makeNewScope(tree, sym)).typedClassDef(tree) case tree @ ModuleDef(_, _, _) => - newTyper(makeNewScope(context, tree, sym.moduleClass)).typedModuleDef(tree) + newTyper(context.makeNewScope(tree, sym.moduleClass)).typedModuleDef(tree) case vdef @ ValDef(_, _, _, _) => typedValDef(vdef) case ddef @ DefDef(_, _, _, _, _, _) => - newTyper(makeNewScope(context, tree, sym)).typedDefDef(ddef) + newTyper(context.makeNewScope(tree, sym)).typedDefDef(ddef) case tdef @ TypeDef(_, _, _, _) => - newTyper(makeNewScope(context, tree, sym)).typedTypeDef(tdef) + newTyper(context.makeNewScope(tree, sym)).typedTypeDef(tdef) case ldef @ LabelDef(_, _, _) => labelTyper(ldef).typedLabelDef(ldef) @@ -2712,7 +2773,7 @@ trait Typers { self: Analyzer => typedAnnotated(annot, typed(arg, mode, pt)) case tree @ Block(_, _) => - newTyper(makeNewScope(context, tree, context.owner)) + newTyper(context.makeNewScope(tree, context.owner)) .typedBlock(tree, mode, pt) case Sequence(elems) => @@ -2753,9 +2814,9 @@ trait Typers { self: Analyzer => case tree @ Function(_, _) => if (tree.symbol == NoSymbol) - tree.symbol = context.owner.newValue(tree.pos, nme.ANON_FUN_NAME) - .setFlag(SYNTHETIC).setInfo(NoType) - newTyper(makeNewScope(context, tree, tree.symbol)).typedFunction(tree, mode, pt) + tree.symbol = recycle(context.owner.newValue(tree.pos, nme.ANON_FUN_NAME) + .setFlag(SYNTHETIC).setInfo(NoType)) + newTyper(context.makeNewScope(tree, tree.symbol)).typedFunction(tree, mode, pt) case Assign(lhs, rhs) => typedAssign(lhs, rhs) @@ -2763,11 +2824,12 @@ trait Typers { self: Analyzer => case If(cond, thenp, elsep) => typedIf(cond, thenp, elsep) - case Match(selector, cases) => + case tree @ Match(selector, cases) => if (selector == EmptyTree) { val arity = if (isFunctionType(pt)) pt.normalize.typeArgs.length - 1 else 1 val params = for (i <- List.range(0, arity)) yield - ValDef(Modifiers(PARAM | SYNTHETIC), unit.fresh.newName("x$"), TypeTree(), EmptyTree) + ValDef(Modifiers(PARAM | SYNTHETIC), + unit.fresh.newName(tree.pos, "x" + i + "$"), TypeTree(), EmptyTree) val ids = for (p <- params) yield Ident(p.name) val selector1 = atPos(tree.pos) { if (arity == 1) ids.head else gen.mkTuple(ids) } val body = copy.Match(tree, selector1, cases) @@ -2920,14 +2982,14 @@ trait Typers { self: Analyzer => copy.TypeBoundsTree(tree, lo1, hi1) setType mkTypeBounds(lo1.tpe, hi1.tpe) case etpt @ ExistentialTypeTree(_, _) => - newTyper(makeNewScope(context, tree, context.owner)).typedExistentialTypeTree(etpt) + newTyper(context.makeNewScope(tree, context.owner)).typedExistentialTypeTree(etpt) case TypeTree() => // we should get here only when something before failed // and we try again (@see tryTypedApply). In that case we can assign // whatever type to tree; we just have to survive until a real error message is issued. tree setType AnyClass.tpe - + case EmptyTree if inIDE => EmptyTree // just tolerate it in the IDE. case _ => throw new Error("unexpected tree: " + tree.getClass + "\n" + tree)//debug } |