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 + -
显示快捷键?