aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/dotc/core/Contexts.scala
blob: 451d8edd33397326738fc7197b5a9f72bbfc9e8b (plain) (tree)
1
2
3
4
5
6
7
8
9







                        
                
                                                               

                           

                                  
                                                


                 


















                                                                                              



                                             
                                        
                                            
                                    
























                                                                                           








                                                                                                         




                                                         


                                                                    
 
                                                   
                                
                                  
                            
                                
                                  
                              
                                 
                                                        
 




                                                   

                                             



                               


                                                         
                              

            

   


                                                        


                                                                                                       

                                                                                                            
                                                                          
                                                                                       
                                                                                                                 

   



                                                                            

                                          
                    

   
                                    
                                  
   
 
                                                                          
                                                  
 
                                    
 
                                                      
                                            
 
                                   
 
                                                   
 







                                                                       
 
                    





                                          

                                                                              
 

                                                                         




                                                      


                                            
                                                          




                                  
 
                           









                                                                                           

   



                                                           

                                                              









                                                                 
 
package dotty.tools.dotc
package core

import Decorators._
import Periods._
import Names._
import Phases._
import Types._
import Symbols._
import TypeComparers._, Printers._, NameOps._, SymDenotations._
import config.Settings._
import config.ScalaSettings
import collection.mutable
import collection.immutable.BitSet
import config.{Settings, Platform, JavaPlatform}

object Contexts {

  /** A context is passed basically everywhere in dotc.
   *  This is convenient but carries the risk of captured contexts in
   *  objects that turn into space leaks. To combat this risk, here are some
   *  conventions to follow:
   *
   *    - Never let an implicit context be an argument of a class whose instances
   *      live longer than the context.
   *    - Classes that need contexts for their initialization take an explicit parameter
   *      named `initctx`. They pass initctx to all positions where it is needed
   *      (and these positions should all be part of the intialization sequence of the class).
   *    - Classes that need contexts that survive initialization are passed
   *      a "condensed context", typically named `cctx` instead. Consensed contexts
   *      just add some basic information to the context base without the
   *      risk of capturing complete trees.
   *    - To make sure these rules are kept, it would be good to do a sanity
   *      check using bytecode inspection with javap or scalap: Keep track
   *      of all class fields of type context; allow them only in whitelisted
   *      classes (which should be short-lived).
   */
  abstract class Context extends Periods
                            with Substituters
                            with TypeOps
                            with Printers
                            with Symbols
                            with Cloneable {
    implicit val ctx: Context = this

    def base: ContextBase

    private[this] var _underlying: Context = _
    protected def underlying_=(underlying: Context) = _underlying = underlying
    def underlying: Context = _underlying

    private[this] var _period: Period = _
    protected def period_=(period: Period) = _period = period
    def period: Period = _period

    private[this] var _constraints: Constraints = _
    protected def constraints_=(constraints: Constraints) = _constraints = constraints
    def constraints: Constraints = _constraints

    private[this] var _typeComparer: TypeComparer = _
    protected def typeComparer_=(typeComparer: TypeComparer) = _typeComparer = typeComparer

    def typeComparer: TypeComparer = {
      if ((_typeComparer eq underlying.typeComparer) &&
          (constraints ne underlying.constraints))
        _typeComparer = new TypeComparer(this)
      _typeComparer
    }

    private[this] var _plainPrinter: Context => Printer = _
    protected def plainPrinter_=(plainPrinter: Context => Printer) = _plainPrinter = plainPrinter
    def plainPrinter: Context => Printer = _plainPrinter

    private[this] var _refinedPrinter: Context => Printer = _
    protected def refinedPrinter_=(refinedPrinter: Context => Printer) = _refinedPrinter = refinedPrinter
    def refinedPrinter: Context => Printer = _refinedPrinter

    def printer = if (base.settings.debug.value) plainPrinter else refinedPrinter

    private[this] var _owner: Symbol = _
    protected def owner_=(owner: Symbol) = _owner = owner
    def owner: Symbol = _owner

    private[this] var _sstate: SettingsState = _
    protected def sstate_=(sstate: SettingsState) = _sstate = sstate
    def sstate: SettingsState = _sstate

    def phase: Phase = ??? // phase(period.phaseId)
    def enclClass: Context = ???
    def erasedTypes: Boolean = ???
    def debug: Boolean = ???
    def error(msg: String) = ???
    def warning(msg: String) = ???
    def log(msg: String) = ???
    def inform(msg: String) = ???
    def informTime(msg: String, start: Long): Unit = ???

    private var _condensed: CondensedContext = null
    def condensed: CondensedContext = {
      if (_condensed == null)
        _condensed = base.initialCtx.fresh
          .withPeriod(period)
          .withPlainPrinter(plainPrinter)
          .withRefinedPrinter(refinedPrinter)
          .withSettings(sstate)
      _condensed
    }

    def fresh: FreshContext = {
      val newctx = super.clone.asInstanceOf[FreshContext]
      newctx.underlying = this
      newctx._condensed = null
      newctx
    }
  }

  abstract class CondensedContext extends Context

  abstract class FreshContext extends CondensedContext {
    def withPeriod(period: Period): this.type = { this.period = period; this }
    def withPhase(pid: PhaseId): this.type = withPeriod(Period(runId, pid))
    def withConstraints(constraints: Constraints): this.type = { this.constraints = constraints; this }
    def withPlainPrinter(printer: Context => Printer): this.type = { this.plainPrinter = printer; this }
    def withRefinedPrinter(printer: Context => Printer): this.type = { this.refinedPrinter = printer; this }
    def withOwner(owner: Symbol): this.type = { this.owner = owner; this }
    def withSettings(sstate: SettingsState): this.type = { this.sstate = sstate; this }
    def withDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this }
  }

  private class InitialContext(val base: ContextBase) extends FreshContext {
    underlying = NoContext
    period = Nowhere
    constraints = Map()
    plainPrinter = new PlainPrinter(_)
    refinedPrinter = new RefinedPrinter(_)
    owner = NoSymbol
  }

  object NoContext extends Context {
    def base = unsupported("base")
  }

  class ContextBase extends ContextState with Transformers.TransformerBase
                       with Printers.PrinterBase {

    val settings = new ScalaSettings

    val initialCtx: Context = new InitialContext(this)
        .withSettings(settings.defaultState)

    val loaders = new SymbolLoaders

    val platform: Platform = new JavaPlatform(this)

    val rootLoader: ClassCompleter = platform.rootLoader

    val definitions = new Definitions()(initialCtx)

  }

  /** Mutable state of a context base, collected into a common class */
  class ContextState {

    // Symbols state

    /** A counter for unique ids */
    private[core] var _nextId = 0

    def nextId = { _nextId += 1; _nextId }

    /** A map from a superclass id to the type-ref of the class that has it */
    private[core] var classOfId = new Array[TypeRef](InitialSuperIdsSize)

    /** A map from a the type-ref of a superclass to its superclass id */
    private[core] val superIdOfClass = new mutable.HashMap[TypeRef, Int]

    /** The last allocate superclass id */
    private[core] var lastSuperId = -1

    /** Allocate and return next free superclass id */
    private[core] def nextSuperId: Int = {
      lastSuperId += 1;
      if (lastSuperId >= classOfId.length) {
        val tmp = new Array[TypeRef](classOfId.length * 2)
        classOfId.copyToArray(tmp)
        classOfId = tmp
      }
      lastSuperId
    }

    // SymDenotations state
    private[core] val uniqueBits = new util.HashSet[BitSet]("superbits", 1024)

    // Types state
    private[core] val uniques = new util.HashSet[Type]("uniques", initialUniquesCapacity) {
      override def hash(x: Type): Int = x.hash
    }

    // TypeOps state
    private[core] var volatileRecursions: Int = 0
    private[core] val pendingVolatiles = new mutable.HashSet[Type]
  }

  object Context {
    implicit def toPrinter(ctx: Context) = ctx.printer(ctx)
  }

  implicit def ctxToBase(ctx: Context): ContextBase = ctx.base

  /** Initial size of superId table */
  private final val InitialSuperIdsSize = 4096

  /** Initial capacity of uniques HashMap */
  private[core] final val initialUniquesCapacity = 50000

  /** How many recursive calls to isVolatile are performed before
   *  logging starts.
   */
  private[core] final val LogVolatileThreshold = 50
}