summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
blob: ef1b48aeef0fb2630427cc90f53b558039258c96 (plain) (tree)
1
2
3
4
5
6
7
8
9






                                    
                      
                                     
 
                                  

                  
                               
                                                               
   
                                  


                         
                            


                                                                   
                                        
                                             
                                      
                            


                                                                                
                             

                                    
                                       
                                 
                                                            

                                    
                                



      



                             
                                                                                               





                   

                                  
                                                                                
                                                                       

                                                                     

                                                                                     
                                                                                    
                                                                                    
                       

                                           
                                

                                                                                 

                                      
                                 
                         
 

                                                           

                                           
                                                         

                       
 

                                                                                                                    



                      


                                                 

                                                                         

                                       

                                                                                            
       
                                 



                                                                        
                                                 
                                 



                     



                                                           
                                




                                                                           

                                                                
                                              

                                                          
                                          

                                                  
                               

                                   





                                                        
                                 


       
                                  


                                                                                      




                                                               





                                        













                                                                                                    
                          
 
                                            



                                                                                                  


                                                                                               



                                                                                      



                                                                       
     













                                                                       


                                                                         

                                         
                                                                                                                                                                 
     
 

                                                                                          
                                                                               








                                                                                                  
                      








                                                                                   













                                                                                               
     
 





                                                              
                                                                          




                              
                                                                
                                                  

                                                                                     
                                                                                   
                                                 









                                                                                      
                                                                                       

               
       
                                                                                                                  



                                                

                                       

                                                                               
                                                              
                                                                                                                                                 
                                                                            
                                                                     
                                                                                            






                                                                   
       
                    


     
                                                      





                                                                                                            












                                                                       
                                   



                                                                                      
                                         





                                              
   
 






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

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

trait Contexts requires Analyzer {
  import global._;

  val NoContext = new Context {
    override def implicitss: List[List[ImplicitInfo]] = List();
  }
  NoContext.enclClass = NoContext;

  val startContext = {
    import definitions._;
    var sc = NoContext.make(
        Template(List(), List()) setSymbol NoSymbol setType NoType,
        definitions.RootClass,
        definitions.RootClass.info.decls);
    def addImport(pkg: Symbol): unit = {
      assert(pkg != null, "package is null");
      val qual = gen.mkStableRef(pkg);
      sc = sc.makeNewImport(
          Import(qual, List(Pair(nme.WILDCARD, null)))
          setSymbol NoSymbol.newImport(Position.NOPOS).setInfo(ImportType(qual))
          setType NoType);
      sc.depth = sc.depth + 1
    }
    if (!settings.noimports.value) {
      assert(isDefinitionsInitialized);
      addImport(JavaLangPackage);
      assert(ScalaPackage != null, "Scala package is null");
      addImport(ScalaPackage);
      if (!settings.nopredefs.value)
        addImport(PredefModule);
    }
    sc
  }

  def resetContexts: unit = {
    var sc = startContext;
    while (sc != NoContext) {
      sc.tree match {
	case Import(qual, _) => qual.tpe = singleType(qual.symbol.owner.thisType, qual.symbol);
	case _ =>
      }
      sc = sc.outer
    }
  }

  class Context {
    var unit: CompilationUnit = _;
    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
    var enclClass: Context = _;             // The next outer context whose tree is a
                                            // template or package definition
    var variance: int = _;                  // Variance relative to enclosing class.
    private var _undetparams: List[Symbol] = List(); // Undetermined type parameters
    var depth: int = 0;
    var imports: List[ImportInfo] = List();

    var prefix: Type = NoPrefix;
    var inConstructorSuffix = false;         // are we in a secondary constructor
                                             // after the this constructor call?
    var reportAmbiguousErrors = false;
    var reportGeneralErrors = false;
    var implicitsEnabled = false;
    var checking = false;

    var savedTypeBounds: List[Pair[Symbol, Type]] = List();

    def undetparams = _undetparams;
    def undetparams_=(ps: List[Symbol]) = {
      //System.out.println("undetparams = " + ps);//debug
      _undetparams = ps
    }

    def make(unit: CompilationUnit, tree: Tree, owner: Symbol, scope: Scope, imports: List[ImportInfo]): Context = {
      val c = new Context;
      c.unit = unit;
      c.tree = tree;
      c.owner = owner;
      c.scope = scope;
      tree match {
        case Template(_, _) | PackageDef(_, _) =>
	  c.enclClass = c;
	  c.prefix = skolemizedThisType(this.tree, this.prefix, c.owner);
          c.inConstructorSuffix = false;
	case _ =>
	  c.enclClass = this.enclClass;
          c.prefix = if (c.owner != this.owner && c.owner.isTerm) NoPrefix else this.prefix;
          c.inConstructorSuffix = this.inConstructorSuffix;
      }
      c.variance = this.variance;
      c.depth = if (scope == this.scope) this.depth else this.depth + 1;
      c.imports = imports;
      c.reportAmbiguousErrors = this.reportAmbiguousErrors;
      c.reportGeneralErrors = this.reportGeneralErrors;
      c.implicitsEnabled = this.implicitsEnabled;
      c.checking = this.checking;
      c.outer = this;
      c
    }

    def make(unit: CompilationUnit): Context = {
      val c = make(unit, EmptyTree, owner, scope, imports);
      c.reportAmbiguousErrors = true;
      c.reportGeneralErrors = true;
      c.implicitsEnabled = true;
      c
    }

    def makeNewImport(imp: Import): Context =
      make(unit, imp, owner, scope, new ImportInfo(imp, depth) :: imports);

    def make(tree: Tree, owner: Symbol, scope: Scope): Context =
      make(unit, tree, owner, scope, imports);

    def makeNewScope(tree: Tree, owner: Symbol): Context =
      make(tree, owner, new Scope(scope));

    def make(tree: Tree, owner: Symbol): Context =
      make(tree, owner, scope);

    def make(tree: Tree): Context =
      make(tree, owner);

    def makeImplicit(reportAmbiguousErrors: boolean) = {
      val c = make(tree);
      c.reportAmbiguousErrors = reportAmbiguousErrors;
      c.reportGeneralErrors = false;
      c.implicitsEnabled = false;
      c
    }

    def makeConstructorContext = {
      var baseContext = enclClass.outer;
      //todo: find out why we need next line
      while (baseContext.tree.isInstanceOf[Template]) baseContext = baseContext.outer;
      val argContext = baseContext.makeNewScope(tree, owner);
      for (val sym <- scope.toList) argContext.scope enter sym;
      argContext
    }

    def makeConstructorSuffixContext = {
      val c = make(tree);
      c.inConstructorSuffix = true;
      c
    }

    def skolemizedThisType(encl: Tree, pre: Type, clazz: Symbol): Type = if (settings.Xgadt.value) {
      encl match {
        case ClassDef(_, _, tparamdefs, _, _) =>
          System.out.println("sktt " + clazz);
          if (!tparamdefs.isEmpty || pre.isInstanceOf[SingleType]) {
            val tparams = clazz.unsafeTypeParams;
            val tskolems = tparamdefs map (.symbol);
            System.out.println("sktt2 " + tparams + " " + tskolems);
            val self = clazz.newThisSkolem setInfo clazz.typeOfThis.substSym(tparams, tskolems);
            singleType(pre, self)
          } else clazz.thisType
        case _ =>
          clazz.thisType
      }
    } else clazz.thisType;

    def error(pos: int, msg: String): unit =
      if (reportGeneralErrors)
        unit.error(pos, if (checking) "**** ERROR DURING INTERNAL CHECKING ****\n" + msg else msg)
      else
        throw new TypeError(msg);

    def ambiguousError(pos: int, pre: Type, sym1: Symbol, sym2: Symbol, rest: String): unit = {
      val msg =
	("ambiguous reference to overloaded definition,\n" +
	 "both " + sym1 + sym1.locationString + " of type " + pre.memberType(sym1) +
	 "\nand  " + sym2 + sym2.locationString + " of type " + pre.memberType(sym2) +
         "\nmatch " + rest);
      if (reportAmbiguousErrors) {
        if (!pre.isErroneous && !sym1.isErroneous && !sym2.isErroneous)
          unit.error(pos, msg)
      } else throw new TypeError(msg);
    }

    def outerContext(clazz: Symbol): Context = {
      var c = this;
      while (c != NoContext && c.owner != clazz) c = c.outer.enclClass;
      c
    }

    def isLocal(): boolean = tree match {
      case Block(_,_) => true
      case PackageDef(_, _) => false
      case EmptyTree => false
      case _ => outer.isLocal()
    }

    def nextEnclosing(p: Context => boolean): Context =
      if (this == NoContext || p(this)) this else outer.nextEnclosing(p);

    override def toString(): String = {
      if (this == NoContext) "NoContext";
      else owner.toString() + " @ " + tree.getClass() + " " + tree.toString() + ", scope = " + scope.hashCode() + " " + scope.toList + "\n:: " + outer.toString()
    }

    /** Is `sym' accessible as a member of tree `site' with type `pre' in current context?
     */
    def isAccessible(sym: Symbol, pre: Type, superAccess: boolean): boolean = {

      /** Are we inside definition of `owner'? */
      def accessWithin(owner: Symbol): boolean = {
	var c = this;
	while (c != NoContext && c.owner != owner) {
	  if (c.outer == null) assert(false, "accessWithin(" + owner + ") " + c);//debug
	  if (c.outer.enclClass == null) assert(false, "accessWithin(" + owner + ") " + c);//debug
	  c = c.outer.enclClass;
	}
	c != NoContext
      }

      /** Is `clazz' a subclass of an enclosing class? */
      def isSubClassOfEnclosing(clazz: Symbol): boolean = {
	var c = this;
	while (c != NoContext && !clazz.isSubClass(c.owner)) c = c.outer.enclClass;
	c != NoContext;
      }

      ( pre == NoPrefix
        ||
        (!sym.hasFlag(PRIVATE | PROTECTED))
        ||
        accessWithin(sym.owner) && (!sym.hasFlag(LOCAL) || pre =:= sym.owner.thisType)
        ||
        (!sym.hasFlag(PRIVATE) &&
         (superAccess ||
	  (pre.widen.symbol.isSubClass(sym.owner) && isSubClassOfEnclosing(pre.widen.symbol))))
      ) && (
        sym.privateWithin == NoSymbol
        ||
        accessWithin(sym.privateWithin)
      )
    }

    def pushTypeBounds(sym: Symbol): unit = {
      savedTypeBounds = Pair(sym, sym.info) :: savedTypeBounds
    }

    def restoreTypeBounds: unit = {
      for (val Pair(sym, info) <- savedTypeBounds) {
        if (settings.debug.value) log("resetting " + sym + " to " + info);
        sym.setInfo(info);
      }
      savedTypeBounds = List()
    }

    private var implicitsCache: List[List[ImplicitInfo]] = null;
    private var implicitsRun: CompilerRun = NoRun;

    private def collectImplicits(syms: List[Symbol], pre: Type): List[ImplicitInfo] =
      for (val sym <- syms; sym.hasFlag(IMPLICIT) && isAccessible(sym, pre, false))
      yield new ImplicitInfo(sym.name, pre, sym);

    private def collectImplicitImports(imp: ImportInfo): List[ImplicitInfo] = {
      val pre = imp.qual.tpe;
      def collect(sels: List[Pair[Name, Name]]): List[ImplicitInfo] = sels match {
	case List() => List()
	case List(Pair(nme.WILDCARD, _)) => collectImplicits(pre.implicitMembers, pre)
	case Pair(from, to) :: sels1 =>
	  var impls = collect(sels1) filter (info => info.name != from);
	  if (to != nme.WILDCARD) {
	    val sym = imp.importedSymbol(to);
	    if (sym.hasFlag(IMPLICIT)) impls = new ImplicitInfo(to, pre, sym) :: impls;
	  }
	  impls
      }
      if (settings.debug.value) log("collect implicit imports " + imp + "=" + collect(imp.tree.selectors));//debug
      collect(imp.tree.selectors)
    }

    def implicitss: List[List[ImplicitInfo]] = {
      if (implicitsRun != currentRun) {
	implicitsRun = currentRun;
	val newImplicits: List[ImplicitInfo] =
	  if (owner != outer.owner && owner.isClass && !owner.isPackageClass) {
            if (!owner.isInitialized) return outer.implicitss;
	    if (settings.debug.value) log("collect member implicits " + owner + ", implicit members = " + owner.thisType.implicitMembers);//debug
	    collectImplicits(owner.thisType.implicitMembers, owner.thisType)
	  } else if (scope != outer.scope && !owner.isPackageClass) {
	    if (settings.debug.value) log("collect local implicits " + scope.toList);//debug
	    collectImplicits(scope.toList, NoPrefix)
	  } else if (imports != outer.imports) {
	    assert(imports.tail == outer.imports);
	    collectImplicitImports(imports.head)
	  } else List();
	implicitsCache = if (newImplicits.isEmpty) outer.implicitss
			 else newImplicits :: outer.implicitss;
      }
      implicitsCache
    }
  }

  class ImportInfo(val tree: Import, val depth: int) {

    /** The prefix expression */
    def qual: Tree = tree.symbol.info match {
      case ImportType(expr) => expr
      case _ => throw new FatalError("symbol " + tree.symbol + " has bad type: " + tree.symbol.info);//debug
    }

    /** Is name imported explicitly, not via wildcard? */
    def isExplicitImport(name: Name): boolean =
      tree.selectors exists (._2.==(name.toTermName));

    /** The symbol with name `name' imported from import clause `tree'.
     */
    def importedSymbol(name: Name): Symbol = {
      var result: Symbol = NoSymbol;
      var renamed = false;
      var selectors = tree.selectors;
      while (selectors != Nil && result == NoSymbol) {
        if (selectors.head._2 == name.toTermName)
	  result = qual.tpe.member(
            if (name.isTypeName) selectors.head._1.toTypeName else selectors.head._1);
        else if (selectors.head._1 == name.toTermName)
          renamed = true
        else if (selectors.head._1 == nme.WILDCARD && !renamed)
          result = qual.tpe.member(name);
        selectors = selectors.tail
      }
      result
    }

    override def toString() = tree.toString();
  }

  class ImplicitInfo(val name: Name, pre: Type, val sym: Symbol) {
    private var tpeCache: Type = null;
    def tpe: Type = {
      if (tpeCache == null) tpeCache = pre.memberType(sym)
      tpeCache
    }
  }

  val NoImplicitInfo = new ImplicitInfo(null, null, null)

  case class ImportType(expr: Tree) extends Type;
}