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


                          

                                   
 
                     
                                                 
                                          
 

                  
                           

                
                                  
                 
 
                               
                                                              
                
   

                                  
 

                              
                                                                                                 


                                            
 



                                                    
                                                                                




                                      





                                                                                                         



               

                                                   
 
                                                                                       

                         
                                
                         
                                               
                            
                                                
                                                                                               
                         
                   
     

                                        



                                                               
     

   
                       
                         

                             

                                                                                              



                   
                                      
                                 
                                                           
                                                    


                                                                                     
                                                                             
                                                                                            
                                                                                   

                                                                                      
                      


                                                                                  
                               

                                                                                
                                                                                            



                                     
                        
 

                                                                           
 








                                           
                               

                             

                                      




                                             
                                       








                                                   




                                                          
                               
                           





                                                       
                                                                       




                                                                           
                                                 

                                                              


                                                 




                                                    









                                                                                                                                  








                                                          
         
                  
                     
                                                                                
           
         
           
                     


     
                                  
                                           
                                                         

                       
 







                          

                                                                  

                         
                             

                     






                                                     
                  
                                                    
                         
                                     
                                       
                 
                                                


                                                                 
                                                          
       



                                        
                                                  
       






                                                                       
                                
                                          


       
                                                



                                                          



                                             
                                                                          
 






                                                                               
                                             
     
 


                                                                                              

                                                  
                               

                                   
                       
 
                                                               
                        
                                   



                                                     
                                                        
                                               
                                


       
                                  
                                       
                                            

                                                     
                                                                                   

                                                                   












                                                      


                
                  
                                        

                                  


       
                                          
                                
                                       

                                                                                                  
                 

     
                                           
                              

                                                                                                  
                                     

     
                                              

                                                     
 






                       
                                                              
                                                    
               


                                                                                      
                           


                                                                       
                                          
     

                                                

                                                                      


       
                                         





                                    
                                                       
                                                                        
 
                                       
                                        


                                                                    
     
 

                                                                                   

                                                              


                                                                                                












                                                                                         

                                                                           
      

                              
                              
                              
       
                                                                               

                                                 
                                                  

                                                    

                                                                            

                                                                                                  


                               


                                                         
                                                         
                                                      
 
                                                                        



                                                                 

                                              
                                                   

                                                                     


                                                                     

                                   
                        

                                                                                
                                                                                  

                                                                                   
       
     
 
                                     
                                                          

     

                                             
                                            
                                                                          

                                                                

                                                                                                             

                   
                         

                              
             

     
                                                               
                                        
 




                                                          
                                                                                     
                                                                                 
                                                

                                                                               
                            
                                                                              
                             

                                                                                  





                                                                                      
       

                                                                                         



                                                




                                                                  
                                                                            
                                           
                                     
                               
                                              

                                                                                   


                                                                                 




                                                                                      
                                                                         


                                                                   

                                                     

                                                

                                                                       
       
                    
     






















                                                                                 
 
   
                                                      


                                             
                            

                                                                                                            

                                                         
                                               
                                                     
 

                                                                          

                                              


                                    
                                                      


                                                                            
                                                 
                                   
                                                                                     


                                                               
                                        




                                  
                                             






                                                               
   
 
                                                                      
                                     
                     
                                                          

              











                                                   
                                                                                
   
 
                                                         
 







                                                                                
                                                      
   
                                           
 
 
/* NSC -- new Scala compiler
 * Copyright 2005-2009 LAMP/EPFL
 * @author  Martin Odersky
 */
// $Id$

package scala.tools.nsc.typechecker

import symtab.Flags._
import scala.tools.nsc.util.{Position,NoPosition}
import scala.collection.mutable.ListBuffer

/** This trait ...
 *
 *  @author  Martin Odersky
 *  @version 1.0
 */
trait Contexts { self: Analyzer =>
  import global._

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

  private val startContext = {
    NoContext.make(
    global.Template(List(), emptyValDef, List()) setSymbol global.NoSymbol setType global.NoType,
    global.definitions.RootClass,
    global.definitions.RootClass.info.decls)
  }

  /** List of objects and packages to import from in
   *  a root context.  This list is sensitive to the
   *  compiler settings.
   */
  protected def rootImports(unit: CompilationUnit, tree: Tree): List[Symbol] = {
    import definitions._
    val imps = new ListBuffer[Symbol]
    if (!settings.noimports.value) {
      assert(isDefinitionsInitialized)
      imps += JavaLangPackage
      if (!unit.isJava) {
        assert(ScalaPackage ne null, "Scala package is null")
        imps += ScalaPackage
        if (!(treeInfo.isPredefUnit(unit.body) || treeInfo.containsLeadingPredefImport(List(unit.body))))
          imps += PredefModule
      }
    }
    imps.toList
  }

  def rootContext(unit: CompilationUnit): Context =
    rootContext(unit, EmptyTree, false)

  def rootContext(unit: CompilationUnit, tree: Tree, erasedTypes: Boolean): Context = {
    import definitions._
    var sc = startContext
    def addImport(pkg: Symbol) {
      assert(pkg ne null)
      val qual = gen.mkAttributedStableRef(pkg)
      sc = sc.makeNewImport(
        Import(qual, List((nme.WILDCARD, null)))
        .setSymbol(NoSymbol.newImport(NoPosition).setFlag(SYNTHETIC).setInfo(ImportType(qual)))
        .setType(NoType))
      sc.depth += 1
    }
    for (imp <- rootImports(unit, tree))
      addImport(imp)
    val c = sc.make(unit, tree, sc.owner, sc.scope, sc.imports)
    c.reportAmbiguousErrors = !erasedTypes
    c.reportGeneralErrors = !erasedTypes
    c.implicitsEnabled = !erasedTypes
    c
  }

  def resetContexts() {
    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 private[typechecker] {
    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 enclMethod: Context = _             // The next outer context whose tree is a method
    var variance: Int = _                   // Variance relative to enclosing class
    private var _undetparams: List[Symbol] = List() // Undetermined type parameters,
                                                    // not inherited to child contexts
    var depth: Int = 0
    var imports: List[ImportInfo] = List()   // currently visible imports
    var openImplicits: List[Type] = List()   // types for which implicit arguments
                                             // are currently searched
    var prefix: Type = NoPrefix
    var inConstructorSuffix = false         // are we in a secondary constructor
                                            // after the this constructor call?
    var returnsSeen = false                 // for method context: were returns encountered?
    var reportAmbiguousErrors = false
    var reportGeneralErrors = false
    var implicitsEnabled = false
    var checking = false
    var retyping = false

    var savedTypeBounds: List[(Symbol, Type)] = List() // saved type bounds
       // for type parameters which are narrowed in a GADT

    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 fix(what : Context) =
        if (what eq this) txt
        else what
      txt.enclClass = fix(enclClass)
      txt.enclMethod = fix(enclMethod)
      txt.implicitsEnabled = implicitsEnabled
      txt.variance = variance
      txt._undetparams = _undetparams
      txt.depth = depth
      txt.imports = imports
      txt.openImplicits = openImplicits
      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 =>
        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 ne EmptyTree)) 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 fix(txt0 : Context, txt1 : Context) =
          ((this eq txt0) && (that eq txt1)) || (txt0 eq txt1)

        val a3 = fix(outer, that.outer)
        val a4 = fix(enclClass, that.enclClass)
        val a5 = fix(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(openImplicits, that.openImplicits)
        val a11 = eq(prefix, that.prefix)
        val a12 = eq(inConstructorSuffix, that.inConstructorSuffix)
        val a13 = eq(implicitsEnabled, that.implicitsEnabled)
        val a14 = eq(checking, that.checking)
        val a15 = eq(retyping, that.retyping)
        val a16 = eq(savedTypeBounds, that.savedTypeBounds)
        val a17 = eq(unit, that.unit)
        val ret = a0 && a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8 && a9 && a10 && a11 && a12 && a13 && a14 && a15 && a16 && a17
        val a18 = {
          if (implicitsRunId > that.implicitsRunId) {
            that.implicitsRunId = NoRunId
            that.implicitsCache = null
          }
          else if (that.implicitsRunId > implicitsRunId) {
            implicitsRunId = NoRunId
            implicitsCache = null
          }
          implicitsCache == that.implicitsCache
        }
        if (ret) {
          if (!a18) {
            //assert(this.implicitsCache == null || that.implicitsCache == null)
          }
        }
        ret
      case _ => false
    }


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

    /**
     *  @param unit    ...
     *  @param tree    ...
     *  @param owner   ...
     *  @param scope   ...
     *  @param imports ...
     *  @return        ...
     */
    def make(unit: CompilationUnit, tree: Tree, owner: Symbol,
             scope: Scope, imports: List[ImportInfo]): Context = {
      val c = new Context
      c.unit = unit
      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 = internIf(this.enclClass)
          c.prefix =
            if (c.owner != this.owner && c.owner.isTerm) NoPrefix
            else this.prefix
          c.inConstructorSuffix = this.inConstructorSuffix
      }
      tree match {
        case DefDef(_, _, _, _, _, _) =>
          c.enclMethod = c
        case _ =>
          c.enclMethod = internIf(this.enclMethod)
      }
      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.retyping = this.retyping
      c.openImplicits = this.openImplicits
      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 = {
      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)(implicit kind : ScopeKind): Context =
      make(tree, owner, scopeFor(scope, tree, kind))
    // IDE stuff: distinguish between scopes created for typing and scopes created for naming.

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

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

    def makeSilent(reportAmbiguousErrors: Boolean): Context = {
      val c = make(tree)
      c.reportGeneralErrors = false
      c.reportAmbiguousErrors = reportAmbiguousErrors
      c
    }

    def makeImplicit(reportAmbiguousErrors: Boolean) = {
      val c = makeSilent(reportAmbiguousErrors)
      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)(Constructor0ScopeKind)
      argContext.reportGeneralErrors = this.reportGeneralErrors
      argContext.reportAmbiguousErrors = this.reportAmbiguousErrors
      def enterElems(c: Context) {
        def enterLocalElems(e: ScopeEntry) {
          if (e != null && e.owner == c.scope) {
            enterLocalElems(e.next)
            argContext.scope enter e.sym
          }
        }
        if (c.owner.isTerm && !c.owner.isLocalDummy) {
          enterElems(c.outer)
          enterLocalElems(c.scope.elems)
        }
      }
      enterElems(this)
      argContext
    }

    //todo: remove
    def makeConstructorSuffixContext = {
      val c = make(tree)
      c.inConstructorSuffix = true
      c
    }

    def error(pos: Position, err: Error) {
      val msg = err.getMessage()
      if (reportGeneralErrors || inIDE)
        unit.error(pos, if (checking) "**** ERROR DURING INTERNAL CHECKING ****\n" + msg else msg)
      else
        throw err
    }

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

    def warning(pos:  Position, msg: String) {
      if (reportGeneralErrors) unit.warning(pos, msg)
    }

    /**
     *  @param pos  ...
     *  @param pre  ...
     *  @param sym1 ...
     *  @param sym2 ...
     *  @param rest ...
     */
    def ambiguousError(pos: Position, pre: Type, sym1: Symbol,
                       sym2: Symbol, rest: String) {
      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(pos, 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()
    }

    /** Return closest enclosing context that defines a superclass of `clazz', or a
     *  companion module of a superclass of `clazz', or NoContext if none exists */
    def enclosingSuperClassContext(clazz: Symbol): Context = {
      var c = this.enclClass
      while (c != NoContext &&
             !clazz.isNonBottomSubClass(c.owner) &&
             !(c.owner.isModuleClass && clazz.isNonBottomSubClass(c.owner.linkedClassOfModule)))
        c = c.outer.enclClass
      c
    }

    /** Return closest enclosing context that defines a subclass of `clazz', or NoContext
     *  if none exists */
    def enclosingSubClassContext(clazz: Symbol): Context = {
      var c = this.enclClass
      while (c != NoContext && !c.owner.isNonBottomSubClass(clazz))
        c = c.outer.enclClass
      c
    }

    /** Is <code>sym</code> accessible as a member of tree `site' with type
     *  <code>pre</code> in current context?
     *
     *  @param sym         ...
     *  @param pre         ...
     *  @param superAccess ...
     *  @return            ...
     */
    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 (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
        }
        c != NoContext
      }

      /** Is `clazz' a subclass of an enclosing class? */
      def isSubClassOfEnclosing(clazz: Symbol): Boolean =
        enclosingSuperClassContext(clazz) != NoContext

      def isSubThisType(pre: Type, clazz: Symbol): Boolean = pre match {
        case ThisType(pclazz) => pclazz isNonBottomSubClass clazz
        case _ => false
      }

      (pre == NoPrefix) || {
        val ab = sym.accessBoundary(sym.owner)
        ((ab.isTerm || ab == definitions.RootClass)
         ||
         (accessWithin(ab) || accessWithin(ab.linkedClassOfClass)) &&
         (!sym.hasFlag(LOCAL) ||
          (sym hasFlag PROTECTED) && isSubThisType(pre, sym.owner) ||
          pre =:= sym.owner.thisType)
         ||
         (sym hasFlag PROTECTED) &&
         (superAccess ||
          (pre.widen.typeSymbol.isNonBottomSubClass(sym.owner) &&
           (isSubClassOfEnclosing(pre.widen.typeSymbol) || phase.erasedTypes))))
        // note: phase.erasedTypes disables last test, because after addinterfaces
        // implementation classes are not in the superclass chain. If we enable the
        // test, bug780 fails.
      }
    }

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

    def restoreTypeBounds(tp: Type): Type = {
      var current = tp
      for ((sym, info) <- savedTypeBounds) {
        if (settings.debug.value) log("resetting " + sym + " to " + info);
        sym.info match {
          case TypeBounds(lo, hi) if (hi <:< lo && lo <:< hi) =>
            current = current.instantiateTypeParams(List(sym), List(lo))
//@M TODO: when higher-kinded types are inferred, probably need a case PolyType(_, TypeBounds(...)) if ... =>
          case _ =>
        }
        sym.setInfo(info)
      }
      savedTypeBounds = List()
      current
    }

    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)

    private def collectImplicitImports(imp: ImportInfo): List[ImplicitInfo] = {
      val pre = imp.qual.tpe
      def collect(sels: List[(Name, Name)]): List[ImplicitInfo] = sels match {
        case List() => List()
        case List((nme.WILDCARD, _)) => collectImplicits(pre.implicitMembers, pre)
        case (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]] = {
      val nextOuter =
        if (owner.isConstructor) {
          if (outer.tree.isInstanceOf[Template]) outer.outer.outer
          else outer.outer
        } else outer
        // can we can do something smarter to bring back the implicit cache?
      if (implicitsRunId != currentRunId) {
        implicitsRunId = currentRunId
        implicitsCache = List()
        val newImplicits: List[ImplicitInfo] =
          if (owner != nextOuter.owner && owner.isClass && !owner.isPackageClass) {
            if (!owner.isInitialized) return nextOuter.implicitss
            if (settings.debug.value)
              log("collect member implicits " + owner + ", implicit members = " +
                  owner.thisType.implicitMembers)//debug
            val savedEnclClass = enclClass
            this.enclClass = this
            val res = collectImplicits(owner.thisType.implicitMembers, owner.thisType)
            this.enclClass = savedEnclClass
            res
          } else if (scope != nextOuter.scope && !owner.isPackageClass) {
            if (settings.debug.value)
              log("collect local implicits " + scope.toList)//debug
            collectImplicits(scope.toList, NoPrefix)
          } else if (imports != nextOuter.imports) {
            assert(imports.tail == nextOuter.imports)
            collectImplicitImports(imports.head)
          } else List()
        implicitsCache = if (newImplicits.isEmpty) nextOuter.implicitss
                         else newImplicits :: nextOuter.implicitss
      }
      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
    }

  }
  class ImportInfo(val tree: Import, val depth: Int) {
    /** The prefix expression */
    def qual: Tree = tree.symbol.info match {
      case ImportType(expr) => expr
      case ErrorType => tree
      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 <code>name</code> imported from import clause
     *  <code>tree</code>.
     */
    def importedSymbol(name: Name): Symbol = {
      var result: Symbol = NoSymbol
      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)
        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()

    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) {
    private var tpeCache: Type = null
    def tpe: Type = {
      if (tpeCache eq null) tpeCache = pre.memberType(sym)
      tpeCache
    }
    override def equals(other: Any) = other match {
      case that: ImplicitInfo =>
        if (this eq NoImplicitInfo) that eq this
        else
          this.name == that.name &&
          this.pre =:= that.pre &&
          this.sym == that.sym
      case _ =>
        false
    }
    override def hashCode =
      name.hashCode + pre.hashCode + sym.hashCode
    override def toString = "ImplicitInfo(" + name + "," + pre + "," + sym + ")"
  }

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

  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
    override def safeToString = "ImportType("+expr+")"
  }
  protected def intern(txt : Context) = txt

}