summaryrefslogblamecommitdiff
path: root/sources/scala/tools/nsc/typechecker/Namers.scala
blob: 3096d85017c67a7bca6125a1651009e5bfe4616b (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

















                                                               
                                                             











                                                                                        

                                                           
                                                    



                                                                                          

     
                                             


                                                                              
                                            









                                                                    
                                                         




                                                                             
                                                                            

                                    
                                                                     




                                                                              
                                                                                              




                                                      
                          




                                                                                   
                                                                                              

                                    
                                                                      








                                                   
                                                                








                                                                
                                                                     







                                                                                   
                       






                                                                                   
                               
                                          



                                                                       





















                                                                                       
                                                                          
                                                                      


                                                            
                                                                                      

                                              
                                                                              

                                                      
                                                                           




                                     
                              


                                                       
                       





         
/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author  Martin Odersky
 */
// $Id$
package scala.tools.nsc.typechecker;

import scala.tools.util.Position;
import symtab.Flags._;

/** Methods to create symbols and to enter them into scopes. */
trait Namers: Analyzer {
  import global._;

  class NamerPhase(prev: Phase) extends StdPhase(prev) {
    def name = "namer";
    val global: Namers.this.global.type = Namers.this.global;
    def apply(unit: CompilationUnit): unit =
      new Namer(startContext.make(unit)).enterSym(unit.body);
  }

  class Namer(context: Context) {

    val typer = new Typer(context);

    private def doubleDefError(pos: int, sym: Symbol): unit =
      context.unit.error(pos,
        sym.name.toString() + " is already defined as " +
        (if ((sym.rawflags & CASE) != 0) "case class " + sym.name else sym.toString()));

    private def updatePosFlags(sym: Symbol, pos: int, mods: int): Symbol = {
      sym.pos = pos;
      val oldflags = sym.rawflags & (INITIALIZED | LOCKED);
      val newflags = mods & ~(INITIALIZED | LOCKED);
      sym.rawflags = oldflags | newflags;
      if (sym.isModule)
        updatePosFlags(sym.moduleClass, pos, (mods & MODULE2CLASSFLAGS) | MODULE | FINAL);
      sym
    }

    def enterInScope(sym: Symbol): Symbol = {
      if (!(sym.isMethod && sym.owner.isClass)) {
	val prev = context.scope.lookupEntry(sym.name);
	if (prev != null && prev.owner == context.scope && !prev.sym.isMethod)
	  doubleDefError(sym.pos, prev.sym);
      }
      context.scope enter sym;
      sym
    }

    private def enterPackageSymbol(pos: int, name: Name): Symbol = {
      val p: Symbol = context.scope.lookup(name);
      if (p.isPackage && context.scope == p.owner.info.decls) {
        p.pos = pos; p.moduleClass.pos = pos; p
      } else {
        enterInScope(context.owner.newPackage(pos, name))
      }
    }

    private def enterClassSymbol(pos: int, mods: int, name: Name): Symbol = {
      val c: Symbol = context.scope.lookup(name);
      if (c.isType && c.isExternal && context.scope == c.owner.info.decls) {
        updatePosFlags(c, pos, mods)
      } else {
	enterInScope(context.owner.newClass(pos, name).setFlag(mods))
      }
    }

    private def enterModuleSymbol(pos: int, mods: int, name: Name): Symbol = {
      val m: Symbol = context.scope.lookup(name);
      if (m.isModule && !m.isPackage && m.isExternal && context.scope == m.owner.info.decls) {
        updatePosFlags(m, pos, mods)
      } else {
        val newm = context.owner.newModule(pos, name);
        newm.setFlag(mods);
        newm.moduleClass.setFlag(mods);
	enterInScope(newm)
      }
    }

    private def enterCaseFactorySymbol(pos: int, mods: int, name: Name): Symbol = {
      val m: Symbol = context.scope.lookup(name);
      if (m.isModule && !m.isPackage && m.isExternal && context.scope == m.owner.info.decls) {
        updatePosFlags(m, pos, mods)
      } else {
        enterInScope(context.owner.newMethod(pos, name).setFlag(mods))
      }
    }

    def enterSyms(trees: List[Tree]): unit =
      for (val tree <- trees) enterSym(tree);

    def enterSym(tree: Tree): Symbol = {

      def finishWith(tparams: List[AbsTypeDef]) = {
	if (settings.debug.value) log("entered " + tree.symbol);
	val ltype = typer.typeCompleter(tree);
	def makeParam(tparam: AbsTypeDef): Symbol =
	  tree.symbol.newTypeParameter(tparam.pos, tparam.name);
	tree.symbol.setInfo(
	  if (tparams.isEmpty) ltype
	  else new LazyPolyType(tparams map makeParam, ltype))
      }
      def finish = finishWith(List());

      if (tree.symbol != null && tree.symbol != NoSymbol) tree.symbol
      else {
	val owner = context.owner;
	tree match {
	  case PackageDef(name, stats) =>
	    tree.symbol = enterPackageSymbol(tree.pos, name);
	    val namer = new Namer(
	      context.make(tree, tree.symbol.moduleClass, tree.symbol.info.decls));
	    stats map namer.enterSym;
            tree.symbol
	  case ClassDef(mods, name, tparams, _, _) =>
	    if ((mods & (CASE | ABSTRACT)) == CASE) { // enter case factory method.
	      tree.symbol = enterCaseFactorySymbol(
		tree.pos, mods & ACCESSFLAGS | CASE, name.toTermName);
	      finishWith(tparams);
	    }
	    tree.symbol = enterClassSymbol(tree.pos, mods, name);
	    finishWith(tparams)
	  case ModuleDef(mods, name, _) =>
	    tree.symbol = enterModuleSymbol(tree.pos, mods, name);
	    tree.symbol.moduleClass.setInfo(typer.typeCompleter(tree));
	    finish
	  case ValDef(mods, name, tp, rhs) =>
            if (context.owner.isClass & (mods & PRIVATE) == 0) {
	      val accmods = ACCESSOR | (if ((mods & MUTABLE) != 0) mods & ~MUTABLE
                                        else mods | STABLE);
	      val getter = owner.newMethod(tree.pos, name)
	        .setFlag(accmods).setInfo(typer.getterTypeCompleter(tree));
	      enterInScope(getter);
	      if ((mods & MUTABLE) != 0) {
	        val setter = owner.newMethod(tree.pos, name)
		  .setFlag(accmods).setInfo(typer.setterTypeCompleter(tree));
	        enterInScope(setter)
	      }
	      tree.symbol =
	        if ((mods & DEFERRED) == 0)
		  owner.newValue(tree.pos, name)
	            .setFlag(mods | PRIVATE | LOCAL).setInfo(typer.typeCompleter(tree))
	        else getter;
              tree.symbol
            } else {
              tree.symbol =
                enterInScope(owner.newValue(tree.pos, name).setFlag(mods));
	      finish
            }
	  case DefDef(mods, nme.CONSTRUCTOR, tparams, vparams, tp, rhs) =>
	    tree.symbol = enterInScope(owner.newConstructor(tree.pos))
	      .setFlag(mods | owner.rawflags & CONSTRFLAGS);
	    finishWith(tparams)
	  case DefDef(mods, name, tparams, _, _, _) =>
	    tree.symbol = enterInScope(owner.newMethod(tree.pos, name)).setFlag(mods);
	    finishWith(tparams)
	  case AbsTypeDef(mods, name, _, _) =>
	    tree.symbol = enterInScope(owner.newAbstractType(tree.pos, name));
	    finish
	  case AliasTypeDef(mods, name, tparams, _) =>
	    tree.symbol = enterInScope(owner.newAliasType(tree.pos, name));
	    finishWith(tparams)
	  case Attributed(_, defn) =>
	    enterSym(defn)
	  case DocDef(_, defn) =>
	    enterSym(defn)
	  case Import(_, _) =>
	    tree.symbol = NoSymbol.newImport(tree.pos);
	    finish
	  case _ =>
            tree.symbol
	}
      }
    }
  }
}