aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/dotc/typer/ImportInfo.scala
blob: 3aa2891812e4169409e1dc44941a6ef372504b54 (plain) (tree)
1
2
3
4
5
6
7
8
9



                   
                       
                  
             

                                                                                  
                                     
 

                                                                  
                                                                 
                                                    
                                 
                                         
                                                              


   





                                                                                       


                                                                                                                              
 




                                                                 










                                                                                       
                                                                  













                                                                   
                                                                              
                              
                                                                              
                                                 
                              













                                                               
                                          
                  
                           




                                                                        

                                                                            
                                                                           
   
 






                                                                                            
                                                           

                     
                                                                                                

   








                                                                                
 
package dotty.tools
package dotc
package typer

import ast.{tpd, untpd}
import ast.Trees._
import core._
import util.SimpleMap
import Symbols._, Names._, Denotations._, Types._, Contexts._, StdNames._, Flags._
import Decorators.StringInterpolators

object ImportInfo {
  /** The import info for a root import from given symbol `sym` */
  def rootImport(refFn: () => TermRef)(implicit ctx: Context) = {
    val selectors = untpd.Ident(nme.WILDCARD) :: Nil
    def expr = tpd.Ident(refFn())
    def imp = tpd.Import(expr, selectors)
    new ImportInfo(imp.symbol, selectors, isRootImport = true)
  }
}

/** Info relating to an import clause
 *  @param   sym        The import symbol defined by the clause
 *  @param   selectors  The selector clauses
 *  @param   rootImport true if this is one of the implicit imports of scala, java.lang
 *                      or Predef in the start context, false otherwise.
 */
class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], val isRootImport: Boolean = false)(implicit ctx: Context) {

  lazy val sym = symf

  /** The (TermRef) type of the qualifier of the import clause */
  def site(implicit ctx: Context): Type = {
    val ImportType(expr) = sym.info
    expr.tpe
  }

  /** The names that are excluded from any wildcard import */
  def excluded: Set[TermName] = { ensureInitialized(); myExcluded }

  /** A mapping from renamed to original names */
  def reverseMapping: SimpleMap[TermName, TermName] = { ensureInitialized(); myMapped }

  /** The original names imported by-name before renaming */
  def originals: Set[TermName] = { ensureInitialized(); myOriginals }

  /** Does the import clause end with wildcard? */
  def isWildcardImport = { ensureInitialized(); myWildcardImport }

  private var myExcluded: Set[TermName] = null
  private var myMapped: SimpleMap[TermName, TermName] = null
  private var myOriginals: Set[TermName] = null
  private var myWildcardImport: Boolean = false

  /** Compute info relating to the selector list */
  private def ensureInitialized(): Unit = if (myExcluded == null) {
    myExcluded = Set()
    myMapped = SimpleMap.Empty
    myOriginals = Set()
    def recur(sels: List[untpd.Tree]): Unit = sels match {
      case sel :: sels1 =>
        sel match {
          case Thicket(Ident(name: TermName) :: Ident(nme.WILDCARD) :: Nil) =>
            myExcluded += name
          case Thicket(Ident(from: TermName) :: Ident(to: TermName) :: Nil) =>
            myMapped = myMapped.updated(to, from)
            myExcluded += from
            myOriginals += from
          case Ident(nme.WILDCARD) =>
            myWildcardImport = true
          case Ident(name: TermName) =>
            myMapped = myMapped.updated(name, name)
            myOriginals += name
        }
        recur(sels1)
      case nil =>
    }
    recur(selectors)
  }

  /** The implicit references imported by this import clause */
  def importedImplicits: List[TermRef] = {
    val pre = site
    if (isWildcardImport) {
      val refs = pre.implicitMembers
      if (excluded.isEmpty) refs
      else refs filterNot (ref => excluded contains ref.name.toTermName)
    } else
      for {
        renamed <- reverseMapping.keys
        denot <- pre.member(reverseMapping(renamed)).altsWith(_ is Implicit)
      } yield TermRef.withSigAndDenot(pre, renamed, denot.signature, denot)
  }

  /** The root import symbol hidden by this symbol, or NoSymbol if no such symbol is hidden.
   *  Note: this computation needs to work even for un-initialized import infos, and
   *  is not allowed to force initialization.
   */
  lazy val hiddenRoot: Symbol = {
    val sym = site.termSymbol
    def hasMaskingSelector = selectors exists {
      case Thicket(_ :: Ident(nme.WILDCARD) :: Nil) => true
      case _ => false
    }
    if ((defn.RootImportTypes exists (_.symbol == sym)) && hasMaskingSelector) sym else NoSymbol
  }

  override def toString = {
    val siteStr = site.show
    val exprStr = if (siteStr endsWith ".type") siteStr dropRight 5 else siteStr
    val selectorStr = selectors match {
      case Ident(name) :: Nil => name.show
      case _ => "{...}"
    }
    i"import $exprStr.$selectorStr"
  }
}