namers.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,028 行 · 第 1/3 页
SCALA
1,028 行
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author Martin Odersky */// $Id: Namers.scala 14561 2008-04-09 09:57:10Z odersky $package scala.tools.nsc.typecheckerimport scala.collection.mutable.HashMapimport scala.tools.nsc.util.Positionimport symtab.Flagsimport symtab.Flags._/** This trait declares methods to create symbols and to enter them into scopes. * * @author Martin Odersky * @version 1.0 */trait Namers { self: Analyzer => import global._ import definitions._ import posAssigner.atPos /** Convert to corresponding type parameters all skolems which satisfy one * of the following two conditions: * 1. The skolem is a parameter of a class or alias type * 2. The skolem is a method parameter which appears in parameter `tparams' */ class DeSkolemizeMap(tparams: List[Symbol]) extends TypeMap { def apply(tp: Type): Type = tp match { case TypeRef(pre, sym, args) if (sym.isTypeSkolem && (tparams contains sym.deSkolemize)) => mapOver(rawTypeRef(NoPrefix, sym.deSkolemize, args)) case PolyType(tparams1, restpe) => new DeSkolemizeMap(tparams1 ::: tparams).mapOver(tp) case ClassInfoType(parents, decls, clazz) => val parents1 = List.mapConserve(parents)(this) if (parents1 eq parents) tp else ClassInfoType(parents1, decls, clazz) case _ => mapOver(tp) } } private class NormalNamer(context : Context) extends Namer(context) def newNamer(context : Context) : Namer = new NormalNamer(context) private val caseClassOfModuleClass = new HashMap[Symbol, ClassDef] def resetNamer() { caseClassOfModuleClass.clear } abstract class Namer(val context: Context) { val typer = newTyper(context) def setPrivateWithin[Sym <: Symbol](tree: Tree, sym: Sym, mods: Modifiers): Sym = { if (!mods.privateWithin.isEmpty) sym.privateWithin = typer.qualifyingClassContext(tree, mods.privateWithin).owner sym } def inConstructorFlag: Long = if (context.owner.isConstructor && !context.inConstructorSuffix || context.owner.isEarly) INCONSTRUCTOR else 0l def moduleClassFlags(moduleFlags: Long) = (moduleFlags & ModuleToClassFlags) | FINAL | inConstructorFlag def updatePosFlags(sym: Symbol, pos: Position, flags: Long): Symbol = { if (settings.debug.value) log("overwriting " + sym) val lockedFlag = sym.flags & LOCKED sym.reset(NoType) sym setPos pos sym.flags = flags | lockedFlag if (sym.isModule && sym.moduleClass != NoSymbol) updatePosFlags(sym.moduleClass, pos, moduleClassFlags(flags)) if (sym.owner.isPackageClass && (sym.linkedSym.rawInfo.isInstanceOf[loaders.SymbolLoader] || sym.linkedSym.rawInfo.isComplete && runId(sym.validTo) != currentRunId)) // pre-set linked symbol to NoType, in case it is not loaded together with this symbol. sym.linkedSym.setInfo(NoType) sym } private def isTemplateContext(context: Context): Boolean = context.tree match { case Template(_, _, _) => true case Import(_, _) => isTemplateContext(context.outer) case _ => false } private var innerNamerCache: Namer = null protected def makeConstructorScope(classContext : Context) : Context = { val outerContext = classContext.outer.outer outerContext.makeNewScope(outerContext.tree, outerContext.owner)(Constructor1ScopeKind) } def namerOf(sym: Symbol): Namer = { def innerNamer: Namer = { if (innerNamerCache eq null) innerNamerCache = if (!isTemplateContext(context)) this else newNamer(context.make(context.tree, context.owner, scopeFor(context.tree, InnerScopeKind))) innerNamerCache } def primaryConstructorParamNamer: Namer = { //todo: can we merge this with SCCmode? val classContext = context.enclClass 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 } // IDE hook 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())) } private def inCurrentScope(m: Symbol) = if (context.owner.isClass) context.owner == m.owner else context.scope == m.owner.info.decls def enterInScope(sym: Symbol): Symbol = { // allow for overloaded methods if (!(sym.isSourceMethod && sym.owner.isClass && !sym.owner.isPackageClass)) { var prev = context.scope.lookupEntry(sym.name); if ((prev ne null) && inIDE) { var guess = prev while ((guess ne null) && (guess.sym ne sym)) guess = context.scope.lookupNextEntry(guess) if (guess != null) prev = guess while (prev != null && (!prev.sym.hasRawInfo || !prev.sym.rawInfo.isComplete || (prev.sym.sourceFile == null && sym.getClass == prev.sym.getClass))) { if (prev.sym.rawInfo.isComplete) { Console.println("DITCHING: " + prev.sym) } context.scope unlink prev.sym prev = context.scope.lookupNextEntry(prev) } val sym0 = context.scope enter sym if (sym0 ne sym) { assert(true) Console.println("WEIRD: " + sym0) } if (prev != null && (sym0 ne prev.sym) && conflict(sym0,prev.sym)) { doubleDefError(sym0.pos, prev.sym) } sym0 } else if ((prev ne null) && prev.owner == context.scope && conflict(sym, prev.sym)) { doubleDefError(sym.pos, prev.sym) sym setInfo ErrorType // don't do this in IDE for stability context.scope unlink prev.sym // let them co-exist... context.scope enter sym } else context.scope enter sym } else context.scope enter sym } def enterPackageSymbol(pos: Position, name: Name): Symbol = { val cscope = if (context.owner == EmptyPackageClass) RootClass.info.decls else context.scope val p: Symbol = cscope.lookup(name) if (p.isPackage && cscope == p.owner.info.decls) { p } else { val cowner = if (context.owner == EmptyPackageClass) RootClass else context.owner val pkg = cowner.newPackage(pos, name) // IDE: newScope should be ok because packages are never destroyed. if (inIDE) assert(!pkg.moduleClass.hasRawInfo || !pkg.moduleClass.rawInfo.isComplete) pkg.moduleClass.setInfo(new PackageClassInfoType(newScope, pkg.moduleClass, null)) pkg.setInfo(pkg.moduleClass.tpe) enterInScope(pkg) } } def enterClassSymbol(tree : ClassDef): Symbol = { var c: Symbol = context.scope.lookup(tree.name); if (!inIDE && c.isType && c.owner.isPackageClass && context.scope == c.owner.info.decls && !currentRun.compiles(c)) { updatePosFlags(c, tree.pos, tree.mods.flags) setPrivateWithin(tree, c, tree.mods) } else { 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.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(inIDE || !currentRun.compiles(clazz) || clazz.sourceFile == currentRun.symSource(c)); currentRun.symSource(c) = clazz.sourceFile } } assert(c.name.toString.indexOf('(') == -1) c } /** Enter a module symbol. The tree parameter can be either a module definition * or a class definition */ def enterModuleSymbol(tree : ModuleDef): Symbol = { // .pos, mods.flags | MODULE | FINAL, name var m: Symbol = context.scope.lookup(tree.name) val moduleFlags = tree.mods.flags | MODULE | FINAL if (!inIDE && m.isModule && !m.isPackage && inCurrentScope(m) && (!currentRun.compiles(m) || (m hasFlag SYNTHETIC))) { updatePosFlags(m, tree.pos, moduleFlags) setPrivateWithin(tree, m, tree.mods) context.unit.synthetics -= m } else { m = context.owner.newModule(tree.pos, tree.name) m.setFlag(moduleFlags) m = setPrivateWithin(tree, m, tree.mods) m = enterInScope(m) m.moduleClass.setFlag(moduleClassFlags(moduleFlags)) setPrivateWithin(tree, m.moduleClass, tree.mods) } if (m.owner.isPackageClass) { m.moduleClass.sourceFile = context.unit.source.file currentRun.symSource(m) = m.moduleClass.sourceFile } 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 = newNamer(txt) } namer } def newTypeSkolems(tparams: List[Symbol]): List[Symbol] = { val tskolems = tparams map (_.newTypeSkolem) val ltp = new LazyType { override def complete(sym: Symbol) { sym setInfo sym.deSkolemize.info.substSym(tparams, tskolems) //@M the info of a skolem is the skolemized info of the actual type parameter of the skolem } } 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) */ def skolemize(tparams: List[TypeDef]) { val tskolems = newTypeSkolems(tparams map (_.symbol)) for ((tparam, tskolem) <- tparams zip tskolems) tparam.symbol = tskolem } def applicableTypeParams(owner: Symbol): List[Symbol] = if (inIDE && (owner eq NoSymbol)) List() else if (owner.isTerm || owner.isPackageClass) List() else applicableTypeParams(owner.owner) ::: owner.typeParams def deSkolemize: TypeMap = new DeSkolemizeMap(applicableTypeParams(context.owner)) // should be special path for IDE but maybe not.... def enterSym(tree: Tree): Context = { def finishWith(tparams: List[TypeDef]) { val sym = tree.symbol if (settings.debug.value) log("entered " + sym + " in " + context.owner + ", scope-id = " + context.scope.hashCode()); var ltype = namerOf(sym).typeCompleter(tree) if (!tparams.isEmpty) { //@M! TypeDef's type params are handled differently //@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 ? newNamer(context.makeNewScope(tree, sym)(FinishWithScopeKind)).enterSyms(tparams) ltype = new PolyTypeCompleter(tparams, ltype, tree, sym, context) //@M if (sym.isTerm) skolemize(tparams) } setInfo(sym)(ltype) } def finish = finishWith(List()) if (tree.symbol == NoSymbol) { val owner = context.owner tree match { case PackageDef(name, stats) => tree.symbol = enterPackageSymbol(tree.pos, name) val namer = newNamer( context.make(tree, tree.symbol.moduleClass, tree.symbol.info.decls)) namer.enterSyms(stats) case tree @ ClassDef(mods, name, tparams, impl) => tree.symbol = enterClassSymbol(tree) finishWith(tparams) if ((mods.flags & CASE) != 0) { var m: Symbol = context.scope.lookup(tree.name.toTermName).filter(! _.isSourceMethod) if (!(m.isModule && inCurrentScope(m) && currentRun.compiles(m))) { m = enterSyntheticSym(caseModuleDef(tree)) } caseClassOfModuleClass(m.moduleClass) = tree } case tree @ ModuleDef(mods, name, _) => tree.symbol = enterModuleSymbol(tree) tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter((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) var getter = owner.newMethod(tree.pos, name).setFlag(accflags) setPrivateWithin(tree, getter, mods) getter = enterInScope(getter).asInstanceOf[TermSymbol] setInfo(getter)(namerOf(getter).getterTypeCompleter(tree)) if ((mods.flags & MUTABLE) != 0) { var setter = owner.newMethod(tree.pos, nme.getterToSetter(name)) .setFlag(accflags & ~STABLE & ~CASEACCESSOR) setPrivateWithin(tree, setter, mods) setter = enterInScope(setter).asInstanceOf[TermSymbol] setInfo(setter)(namerOf(setter).setterTypeCompleter(tree)) }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?