aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
blob: 2908c541e5e91fe59896ef332c7f0e82c49986a9 (plain) (tree)
1
2
3
4
5
6
7
8
9


                   
             


                                                                                     
                  
                       
                              

                   
                                      

                                          
                                              
                               
                     
                    

                             


                                                                    
   
                                                                                                                      
                      
                        
              
 
                                                                              
                                                            




                                                                                    
                                                          


                                                                             
                                                          

                                                          
 


                                                                                         

                                              




                                                                
                                                                                       

                                      
                                                    
                         
 




                                                                                            


                                                                  
   
 
                            
                                                       
                                                                    
                                                                                    
   
 
                                                                        

                                                                       

                                                
                                                                  




                                             
 

                                                                       
 

                                                    
                                                                   
                                                 
                                                
                                               
 
                            
                                                                    
 


                                                                            
                                                                                     

                             



                                                                        


                                                                               
                   

                                                   



















                                                                                              
                                                                                                 
                                                               


                                            









                                                           
 
                                                       
 
                                                                             
 
                                                                                      
                                               
                  
                             
                  

            

                                                                                                
                                                                              


                                                                                   


















                                                                                                                  
     




                                                   
                                                                        




                                                       
 

                                    
 












                                                                                      
                    
                                


                                               
                                         
                                     

                                                                                 
                                                   

                                                                                            


                                                          
                                                
                             
                                    
                            



                                                                      
                                 
                                                               




                                             
                                                                                                    
                                     
                                                           
                            
                                                  
                              


                                                      

                                   
                                                                        

                              

                                                

                                                              

                                                                                      
       
 
                                                         
                                             

                                                        
                          
                          
                                              
                          
                                  



                                           


                                                                                
           

                                                        

                                                        

                                                      


























                                                                                  

                                            

                                                          

                              
       
 

                                                                          
 








                                                                                                  
       
     
 

                                                                       
                                                                   


                                                              

                             

                            
                                                       


                                                                                   

                                           
                                                   
 



                                                                                 
 
                                                                                                                                                      
                           
                     
                                                                                          
                 
                            
                                                            


                                                                                              
                              
                                            




                                                     
 
                                                                                           
                       








                                               
                                                                   
                                   
       














                                                                                       


                             
                                 
                                                                    
                              
                  
                                
                                          
                                    
                                     
                       
                                

                                 
                                                                  
                                                                                 
                                                                              
                                               
                                                                                      
               
                                                                                           

                                                                                
                             
                                        
                                                                                                   

                                                                       
                                     

                        
                                                                                           
                        



                                                                                                                  

                              
                             
                    
                                         
                                                                      
       
                                  




                                                                                         
                 
         

     
                                                                                 
                        













                                                                                                





                                                   






                                            
                                            
                                        
                                      





                                                 




                                                                    
                                                  
                                        
                                  
                      


                                                 



                                                 
                               
                                                                                 


                                                     

                                                                                   



                                           
 
                                                                            
                                  

                                                                       
       
                                                                 



                                                               

                                       











                                                                            
         


                                            
     











                                                                                            
 
                                                                                
                                          

                                                      



                               
 










                                                                                      
                                

                                                                                              
                                         

                               
 





                                                             






                                                                    

                                          
                                 
                                                              
 
                                      
 


                                                                                     
                                                                                   



                                                                              
 


                                                                   

                                
                           
                                                         
                                       




                                                                

                                                                    

                                                                         




                                                                                                  
                                        
                      


                             
                                   

                                                 

                                                                        
                                                                              
                                                                                  
                                                                               


                                                                              



                                                                                                              
                                           
                  
                               



                                                          
                        
           
                     
                             
                           

                              
           
                
                               
                                        
                                                                          
                                 
           
       
                

                                                                       



                                                                                       
               
                         


                                                                                                               
          
     
 
                                                                 

                                 
                                                              
                                                                                           




                                                                                              
                                        

                                    

                                                         





                                                                             
                                                                                           
                

                                  


                                                                         
                                                                        
                                               
                                                        
 
                                                                                                                                 
                                
                                                               




                                                                           

         




                                                                                   
                   


                                                        
 













                                                                             
                                                 





                                                                                           
                                                                                          
                                       
                        
                    
                    




                                                                               
               
                                            
     
 
                                                     
                             



                                                              
                        
                                 
                    











                                                              
       
                                                  
     
 

                                                                                           
 


                                                                                      

     


                                                                                     



                                                                                
 


                                                                                

                             
                                                                        


                                  
                          
                                              
                                         
                                                                                


                                                        
 



                                                                             
                                                   


                                                                              




                                                                                   
                                              

                                       

                                                      

                                                                 
                      

                                                                          


                                                             
           


                                                


                                                       

                        



                                       
                 
                        




                                    




                                                                                       


                                                                   
                                         




                                                         
                    
                                
                         
                                   

                                                                                               
                         
                                 
                                                    
                                                

                                                            

                               
                                                  

                                                              
                         







                                                                                    




                                              

                              
                                   
                                                                                                

                                                    
                          
                                   

                                                           
                         
                                               




                                                             
                                                                                   
                            

                                                         



                                                                        
                                     




                                                 
                                
                                                       
                            




                                                         









                                                                                  



                                                                                                                              



                                              
                             


                                                                    
                                           

                                                  

                            
           

                                                                                      
       
 
                                                                                     

                                                                                                             
                         
     
 






                                                                 
 
                                                                    






                                                                                       









                                                      
 
                                                                                            
                            
               
                                     
     
 
                                                                            
 
                                                  
                                                                                        

                                            
                                    
                                                                                                 





                                                     


               
   
 
                                                                                                           
                                              
                                                                           
                                                                                              
     
   
 














                                                                                                  

                                          
                                                                                

                

                                                 
                                                                

                                                                
                         
                                          
                   

                                                                           


                                





                                                            


                                
 

                                                                    
 












                                                                                  
package dotty.tools
package dotc
package core
package tasty

import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._
import StdNames._, Denotations._, Flags._, Constants._, Annotations._
import NameKinds._
import util.Positions._
import ast.{tpd, Trees, untpd}
import Trees._
import Decorators._
import TastyUnpickler._, TastyBuffer._
import scala.annotation.{tailrec, switch}
import scala.collection.mutable.ListBuffer
import scala.collection.{ mutable, immutable }
import config.Printers.pickling
import typer.Checking
import config.Config

/** Unpickler for typed trees
 *  @param reader          the reader from which to unpickle
 *  @param tastyName       the nametable
 *  @param posUNpicklerOpt the unpickler for positions, if it exists
 */
class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpicklerOpt: Option[PositionUnpickler]) {
  import TastyFormat._
  import TreeUnpickler._
  import tpd._

  /** A map from addresses of definition entries to the symbols they define */
  private val symAtAddr  = new mutable.HashMap[Addr, Symbol]

  /** A temporary map from addresses of definition entries to the trees they define.
   *  Used to remember trees of symbols that are created by a completion. Emptied
   *  once the tree is inlined into a larger tree.
   */
  private val treeAtAddr = new mutable.HashMap[Addr, Tree]

  /** A map from addresses of type entries to the types they define.
   *  Currently only populated for types that might be recursively referenced
   *  from within themselves (i.e. RecTypes, LambdaTypes).
   */
  private val typeAtAddr = new mutable.HashMap[Addr, Type]

  /** The root symbol denotation which are defined by the Tasty file associated with this
   *  TreeUnpickler. Set by `enterTopLevel`.
   */
  private var roots: Set[SymDenotation] = null

  /** The root symbols that are defined in this Tasty file. This
   *  is a subset of `roots.map(_.symbol)`.
   */
  private var seenRoots: Set[Symbol] = Set()

  /** The root owner tree. See `OwnerTree` class definition. Set by `enterTopLevel`. */
  private var ownerTree: OwnerTree = _

  private def registerSym(addr: Addr, sym: Symbol) =
    symAtAddr(addr) = sym

  /** Enter all toplevel classes and objects into their scopes
   *  @param roots          a set of SymDenotations that should be overwritten by unpickling
   */
  def enterTopLevel(roots: Set[SymDenotation])(implicit ctx: Context): Unit = {
    this.roots = roots
    var rdr = new TreeReader(reader).fork
    ownerTree = new OwnerTree(NoAddr, 0, rdr.fork, reader.endAddr)
    rdr.indexStats(reader.endAddr)
  }

  /** The unpickled trees */
  def unpickle()(implicit ctx: Context): List[Tree] = {
    assert(roots != null, "unpickle without previous enterTopLevel")
    new TreeReader(reader).readTopLevel()(ctx.addMode(Mode.AllowDependentFunctions))
  }

  class Completer(owner: Symbol, reader: TastyReader) extends LazyType {
    import reader._
    def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
      treeAtAddr(currentAddr) =
        new TreeReader(reader).readIndexedDef()(
          ctx.withPhaseNoLater(ctx.picklerPhase).withOwner(owner))
    }
  }

  class TreeReader(val reader: TastyReader) {
    import reader._

    def forkAt(start: Addr) = new TreeReader(subReader(start, endAddr))
    def fork = forkAt(currentAddr)

    def skipTree(tag: Int): Unit =
      if (tag >= firstLengthTreeTag) goto(readEnd())
      else if (tag >= firstNatASTTreeTag) { readNat(); skipTree() }
      else if (tag >= firstASTTreeTag) skipTree()
      else if (tag >= firstNatTreeTag) readNat()
    def skipTree(): Unit = skipTree(readByte())

    def skipParams(): Unit =
      while (nextByte == PARAMS || nextByte == TYPEPARAM) skipTree()

    /** Record all directly nested definitions and templates in current tree
     *  as `OwnerTree`s in `buf`
     */
    def scanTree(buf: ListBuffer[OwnerTree], mode: MemberDefMode = AllDefs): Unit = {
      val start = currentAddr
      val tag = readByte()
      tag match {
        case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | TEMPLATE =>
          val end = readEnd()
          for (i <- 0 until numRefs(tag)) readNat()
          if (tag == TEMPLATE) scanTrees(buf, end, MemberDefsOnly)
          if (mode != NoMemberDefs) buf += new OwnerTree(start, tag, fork, end)
          goto(end)
        case tag =>
          if (mode == MemberDefsOnly) skipTree(tag)
          else if (tag >= firstLengthTreeTag) {
            val end = readEnd()
            var nrefs = numRefs(tag)
            if (nrefs < 0) {
              for (i <- nrefs until 0) scanTree(buf)
              goto(end)
            }
            else {
              for (i <- 0 until nrefs) readNat()
              scanTrees(buf, end)
            }
          }
          else if (tag >= firstNatASTTreeTag) { readNat(); scanTree(buf) }
          else if (tag >= firstASTTreeTag) scanTree(buf)
          else if (tag >= firstNatTreeTag) readNat()
      }
    }

    /** Record all directly nested definitions and templates between current address and `end`
     *  as `OwnerTree`s in `buf`
     */
    def scanTrees(buf: ListBuffer[OwnerTree], end: Addr, mode: MemberDefMode = AllDefs): Unit = {
      while (currentAddr.index < end.index) scanTree(buf, mode)
      assert(currentAddr.index == end.index)
    }

    /** The next tag, following through SHARED tags */
    def nextUnsharedTag: Int = {
      val tag = nextByte
      if (tag == SHARED) {
        val lookAhead = fork
        lookAhead.reader.readByte()
        forkAt(lookAhead.reader.readAddr()).nextUnsharedTag
      }
      else tag
    }

    def readName(): TermName = nameAtRef(readNameRef())

// ------ Reading types -----------------------------------------------------

    /** Read names in an interleaved sequence of (parameter) names and types/bounds */
    def readParamNames(end: Addr): List[Name] =
      until(end) {
        val name = readName()
        skipTree()
        name
      }

    /** Read types or bounds in an interleaved sequence of (parameter) names and types/bounds */
    def readParamTypes[T <: Type](end: Addr)(implicit ctx: Context): List[T] =
      until(end) { readNat(); readType().asInstanceOf[T] }

    /** Read referece to definition and return symbol created at that definition */
    def readSymRef()(implicit ctx: Context): Symbol = symbolAt(readAddr())

    /** The symbol at given address; createa new one if none exists yet */
    def symbolAt(addr: Addr)(implicit ctx: Context): Symbol = symAtAddr.get(addr) match {
      case Some(sym) =>
        sym
      case None =>
        val sym = forkAt(addr).createSymbol()(ctx.withOwner(ownerTree.findOwner(addr)))
        ctx.log(i"forward reference to $sym")
        sym
    }

    /** The symbol defined by current definition */
    def symbolAtCurrent()(implicit ctx: Context): Symbol = symAtAddr.get(currentAddr) match {
      case Some(sym) =>
        assert(ctx.owner == sym.owner, i"owner discrepancy for $sym, expected: ${ctx.owner}, found: ${sym.owner}")
        sym
      case None =>
        createSymbol()
    }

    /** Read a type */
    def readType()(implicit ctx: Context): Type = {
      val start = currentAddr
      val tag = readByte()
      pickling.println(s"reading type ${astTagToString(tag)} at $start")

      def registeringType[T](tp: Type, op: => T): T = {
        typeAtAddr(start) = tp
        op
      }

      def readLengthType(): Type = {
        val end = readEnd()

        def readMethodic[N <: Name, PInfo <: Type, LT <: LambdaType]
            (companion: LambdaTypeCompanion[N, PInfo, LT], nameMap: Name => N): LT = {
          val nameReader = fork
          nameReader.skipTree() // skip result
          val paramReader = nameReader.fork
          val paramNames = nameReader.readParamNames(end).map(nameMap)
          val result = companion(paramNames)(
                pt => registeringType(pt, paramReader.readParamTypes[PInfo](end)),
                pt => readType())
          goto(end)
          result
        }

        val result =
          (tag: @switch) match {
            case SUPERtype =>
              SuperType(readType(), readType())
            case REFINEDtype =>
              var name: Name = readName()
              val parent = readType()
              val ttag = nextUnsharedTag
              if (ttag == TYPEBOUNDS || ttag == TYPEALIAS) name = name.toTypeName
              RefinedType(parent, name, readType())
                // Note that the lambda "rt => ..." is not equivalent to a wildcard closure!
                // Eta expansion of the latter puts readType() out of the expression.
            case APPLIEDtype =>
              readType().appliedTo(until(end)(readType()))
            case TYPEBOUNDS =>
              TypeBounds(readType(), readType())
            case TYPEALIAS =>
              val alias = readType()
              val variance =
                if (nextByte == COVARIANT) { readByte(); 1 }
                else if (nextByte == CONTRAVARIANT) { readByte(); -1 }
                else 0
              TypeAlias(alias, variance)
            case ANNOTATEDtype =>
              AnnotatedType(readType(), Annotation(readTerm()))
            case ANDtype =>
              AndType(readType(), readType())
            case ORtype =>
              OrType(readType(), readType())
            case BIND =>
              val sym = ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType())
              registerSym(start, sym)
              TypeRef.withFixedSym(NoPrefix, sym.name, sym)
            case POLYtype =>
              readMethodic(PolyType, _.toTypeName)
            case METHODtype =>
              readMethodic(MethodType, _.toTermName)
            case TYPELAMBDAtype =>
              readMethodic(HKTypeLambda, _.toTypeName)
            case PARAMtype =>
              readTypeRef() match {
                case binder: LambdaType => binder.newParamRef(readNat())
              }
            case CLASSconst =>
              ConstantType(Constant(readType()))
            case ENUMconst =>
              ConstantType(Constant(readTermRef().termSymbol))
          }
        assert(currentAddr == end, s"$start $currentAddr $end ${astTagToString(tag)}")
        result
      }

      def readSimpleType(): Type = (tag: @switch) match {
        case TYPEREFdirect | TERMREFdirect =>
          NamedType.withFixedSym(NoPrefix, readSymRef())
        case TYPEREFsymbol | TERMREFsymbol =>
          readSymNameRef()
        case TYPEREFpkg =>
          readPackageRef().moduleClass.typeRef
        case TERMREFpkg =>
          readPackageRef().termRef
        case TYPEREF =>
          val name =  readName().toTypeName
          TypeRef(readType(), name)
        case TERMREF =>
          readName() match {
            case SignedName(name, sig) => TermRef.withSig(readType(), name, sig)
            case name => TermRef.all(readType(), name)
          }
        case THIS =>
          ThisType.raw(readType().asInstanceOf[TypeRef])
        case RECtype =>
          RecType(rt => registeringType(rt, readType()))
        case RECthis =>
          RecThis(readTypeRef().asInstanceOf[RecType])
        case SHARED =>
          val ref = readAddr()
          typeAtAddr.getOrElseUpdate(ref, forkAt(ref).readType())
        case UNITconst =>
          ConstantType(Constant(()))
        case TRUEconst =>
          ConstantType(Constant(true))
        case FALSEconst =>
          ConstantType(Constant(false))
        case BYTEconst =>
          ConstantType(Constant(readInt().toByte))
        case SHORTconst =>
          ConstantType(Constant(readInt().toShort))
        case CHARconst =>
          ConstantType(Constant(readNat().toChar))
        case INTconst =>
          ConstantType(Constant(readInt()))
        case LONGconst =>
          ConstantType(Constant(readLongInt()))
        case FLOATconst =>
          ConstantType(Constant(java.lang.Float.intBitsToFloat(readInt())))
        case DOUBLEconst =>
          ConstantType(Constant(java.lang.Double.longBitsToDouble(readLongInt())))
        case STRINGconst =>
          ConstantType(Constant(readName().toString))
        case NULLconst =>
          ConstantType(Constant(null))
        case CLASSconst =>
          ConstantType(Constant(readType()))
        case ENUMconst =>
          ConstantType(Constant(readTermRef().termSymbol))
        case BYNAMEtype =>
          ExprType(readType())
      }

      if (tag < firstLengthTreeTag) readSimpleType() else readLengthType()
    }

    private def readSymNameRef()(implicit ctx: Context): Type = {
      val sym = readSymRef()
      val prefix = readType()
      val res = NamedType.withSymAndName(prefix, sym, sym.name)
      prefix match {
        case prefix: ThisType if prefix.cls eq sym.owner => res.withDenot(sym.denot)
          // without this precaution we get an infinite cycle when unpickling pos/extmethods.scala
          // the problem arises when a self type of a trait is a type parameter of the same trait.
        case _ => res
      }
    }

    private def readPackageRef()(implicit ctx: Context): TermSymbol = {
      val name = readName()
      if (name == nme.ROOT || name == nme.ROOTPKG) defn.RootPackage
      else if (name == nme.EMPTY_PACKAGE) defn.EmptyPackageVal
      else ctx.requiredPackage(name)
    }

    def readTypeRef(): Type =
      typeAtAddr(readAddr())

    def readTermRef()(implicit ctx: Context): TermRef =
      readType().asInstanceOf[TermRef]

// ------ Reading definitions -----------------------------------------------------

    private def noRhs(end: Addr): Boolean =
      currentAddr == end || isModifierTag(nextByte)

    private def localContext(owner: Symbol)(implicit ctx: Context) = {
      val lctx = ctx.fresh.setOwner(owner)
      if (owner.isClass) lctx.setScope(owner.unforcedDecls) else lctx.setNewScope
    }

    private def normalizeFlags(tag: Int, givenFlags: FlagSet, name: Name, isAbsType: Boolean, rhsIsEmpty: Boolean)(implicit ctx: Context): FlagSet = {
      val lacksDefinition =
        rhsIsEmpty &&
          name.isTermName && !name.isConstructorName && !givenFlags.is(ParamOrAccessor) ||
        isAbsType
      var flags = givenFlags
      if (lacksDefinition && tag != PARAM) flags |= Deferred
      if (tag == DEFDEF) flags |= Method
      if (givenFlags is Module)
        flags = flags | (if (tag == VALDEF) ModuleCreationFlags else ModuleClassCreationFlags)
      if (ctx.owner.isClass) {
        if (tag == TYPEPARAM) flags |= Param
        else if (tag == PARAM) flags |= ParamAccessor
      }
      else if (isParamTag(tag)) flags |= Param
      flags
    }

    def isAbstractType(ttag: Int)(implicit ctx: Context): Boolean = nextUnsharedTag match {
      case LAMBDAtpt =>
        val rdr = fork
        rdr.reader.readByte()  // tag
        rdr.reader.readNat()   // length
        rdr.skipParams()       // tparams
        rdr.isAbstractType(rdr.nextUnsharedTag)
      case TYPEBOUNDS | TYPEBOUNDStpt => true
      case _ => false
    }

    /** Create symbol of definition node and enter in symAtAddr map
     *  @return  the created symbol
     */
    def createSymbol()(implicit ctx: Context): Symbol = nextByte match {
      case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM =>
        createMemberSymbol()
      case TEMPLATE =>
        val localDummy = ctx.newLocalDummy(ctx.owner)
        registerSym(currentAddr, localDummy)
        localDummy
      case tag =>
        throw new Error(s"illegal createSymbol at $currentAddr, tag = $tag")
    }

    /** Create symbol of member definition or parameter node and enter in symAtAddr map
     *  @return  the created symbol
     */
    def createMemberSymbol()(implicit ctx: Context): Symbol = {
      val start = currentAddr
      val tag = readByte()
      val end = readEnd()
      var name: Name = readName()
      if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName
      val mname = name.mangled
      skipParams()
      val ttag = nextUnsharedTag
      val isAbsType = isAbstractType(ttag)
      val isClass = ttag == TEMPLATE
      val templateStart = currentAddr
      skipTree() // tpt
      val rhsStart = currentAddr
      val rhsIsEmpty = noRhs(end)
      if (!rhsIsEmpty) skipTree()
      val (givenFlags, annots, privateWithin) = readModifiers(end)
      pickling.println(i"creating symbol $name at $start with flags $givenFlags")
      val flags = normalizeFlags(tag, givenFlags, name, isAbsType, rhsIsEmpty)
      def adjustIfModule(completer: LazyType) =
        if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer
      val sym =
        roots.find(root => (root.owner eq ctx.owner) && root.name.mangled == mname) match {
          case Some(rootd) =>
            pickling.println(i"overwriting ${rootd.symbol} # ${rootd.hashCode}")
            rootd.name = name
            rootd.info = adjustIfModule(
                new Completer(ctx.owner, subReader(start, end)) with SymbolLoaders.SecondCompleter)
            rootd.flags = flags &~ Touched // allow one more completion
            rootd.privateWithin = privateWithin
            seenRoots += rootd.symbol
            rootd.symbol
          case _ =>
            val completer = adjustIfModule(new Completer(ctx.owner, subReader(start, end)))
            if (isClass)
              ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, privateWithin, coord = start.index)
            else
              ctx.newSymbol(ctx.owner, name, flags, completer, privateWithin, coord = start.index)
        } // TODO set position somehow (but take care not to upset Symbol#isDefinedInCurrentRun)
      sym.annotations = annots
      ctx.enter(sym)
      registerSym(start, sym)
      if (isClass) {
        sym.completer.withDecls(newScope)
        forkAt(templateStart).indexTemplateParams()(localContext(sym))
      }
      else if (sym.isInlineMethod)
        sym.addAnnotation(LazyBodyAnnotation { ctx0 =>
          implicit val ctx: Context = localContext(sym)(ctx0).addMode(Mode.ReadPositions)
            // avoids space leaks by not capturing the current context
          forkAt(rhsStart).readTerm()
        })
      goto(start)
      sym
    }

    /** Read modifier list into triplet of flags, annotations and a privateWithin
     *  boundary symbol.
     */
    def readModifiers(end: Addr)(implicit ctx: Context): (FlagSet, List[Annotation], Symbol) = {
      var flags: FlagSet = EmptyFlags
      var annots = new mutable.ListBuffer[Annotation]
      var privateWithin: Symbol = NoSymbol
      while (currentAddr.index != end.index) {
        def addFlag(flag: FlagSet) = {
          flags |= flag
          readByte()
        }
        nextByte match {
          case PRIVATE => addFlag(Private)
          case INTERNAL => ??? // addFlag(Internal)
          case PROTECTED => addFlag(Protected)
          case ABSTRACT =>
            readByte()
            nextByte match {
              case OVERRIDE => addFlag(AbsOverride)
              case _ => flags |= Abstract
            }
          case FINAL => addFlag(Final)
          case SEALED => addFlag(Sealed)
          case CASE => addFlag(Case)
          case IMPLICIT => addFlag(Implicit)
          case LAZY => addFlag(Lazy)
          case OVERRIDE => addFlag(Override)
          case INLINE => addFlag(Inline)
          case STATIC => addFlag(JavaStatic)
          case OBJECT => addFlag(Module)
          case TRAIT => addFlag(Trait)
          case LOCAL => addFlag(Local)
          case SYNTHETIC => addFlag(Synthetic)
          case ARTIFACT => addFlag(Artifact)
          case MUTABLE => addFlag(Mutable)
          case LABEL => addFlag(Label)
          case FIELDaccessor => addFlag(Accessor)
          case CASEaccessor => addFlag(CaseAccessor)
          case COVARIANT => addFlag(Covariant)
          case CONTRAVARIANT => addFlag(Contravariant)
          case SCALA2X => addFlag(Scala2x)
          case DEFAULTparameterized => addFlag(DefaultParameterized)
          case INSUPERCALL => addFlag(InSuperCall)
          case STABLE => addFlag(Stable)
          case PRIVATEqualified =>
            readByte()
            privateWithin = readType().typeSymbol
          case PROTECTEDqualified =>
            addFlag(Protected)
            privateWithin = readType().typeSymbol
          case ANNOTATION =>
            readByte()
            val end = readEnd()
            val tp = readType()
            val lazyAnnotTree = readLater(end, rdr => ctx => rdr.readTerm()(ctx))
            annots += Annotation.deferredSymAndTree(
              implicit ctx => tp.typeSymbol,
              implicit ctx => lazyAnnotTree.complete)
          case tag =>
            assert(false, s"illegal modifier tag $tag at $currentAddr, end = $end")
        }
      }
      (flags, annots.toList, privateWithin)
    }

    /** Create symbols for the definitions in the statement sequence between
     *  current address and `end`.
     *  @return  the largest subset of {NoInits, PureInterface} that a
     *           trait owning the indexed statements can have as flags.
     */
    def indexStats(end: Addr)(implicit ctx: Context): FlagSet = {
      var initsFlags = NoInitsInterface
      while (currentAddr.index < end.index) {
        nextByte match {
          case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM =>
            val sym = symbolAtCurrent()
            skipTree()
            if (sym.isTerm && !sym.is(MethodOrLazyOrDeferred))
              initsFlags = EmptyFlags
            else if (sym.isClass ||
              sym.is(Method, butNot = Deferred) && !sym.isConstructor)
              initsFlags &= NoInits
          case IMPORT =>
            skipTree()
          case PACKAGE =>
            processPackage { (pid, end) => implicit ctx => indexStats(end) }
          case _ =>
            skipTree()
            initsFlags = EmptyFlags
        }
      }
      assert(currentAddr.index == end.index)
      initsFlags
    }

    /** Process package with given operation `op`. The operation takes as arguments
     *   - a `RefTree` representing the `pid` of the package,
     *   - an end address,
     *   - a context which has the processd package as owner
     */
    def processPackage[T](op: (RefTree, Addr) => Context => T)(implicit ctx: Context): T = {
      readByte()
      val end = readEnd()
      val pid = ref(readTermRef()).asInstanceOf[RefTree]
      op(pid, end)(localContext(pid.symbol.moduleClass))
    }

    /** Create symbols the longest consecutive sequence of parameters with given
     *  `tag` starting at current address.
     */
    def indexParams(tag: Int)(implicit ctx: Context) =
      while (nextByte == tag) {
        symbolAtCurrent()
        skipTree()
      }

    /** Create symbols for all type and value parameters of template starting
     *  at current address.
     */
    def indexTemplateParams()(implicit ctx: Context) = {
      assert(readByte() == TEMPLATE)
      readEnd()
      indexParams(TYPEPARAM)
      indexParams(PARAM)
    }

    /** If definition was already read by a completer, return the previously read tree
     *  or else read definition.
     */
    def readIndexedDef()(implicit ctx: Context): Tree = treeAtAddr.remove(currentAddr) match {
      case Some(tree) => skipTree(); tree
      case none => readNewDef()
    }

    private def readNewDef()(implicit ctx: Context): Tree = {
      val start = currentAddr
      val sym = symAtAddr(start)
      val tag = readByte()
      val end = readEnd()

      def readParamss(implicit ctx: Context): List[List[ValDef]] = {
        collectWhile(nextByte == PARAMS) {
          readByte()
          readEnd()
          readParams[ValDef](PARAM)
        }
      }

      def readRhs(implicit ctx: Context) =
        if (noRhs(end)) EmptyTree
        else readLater(end, rdr => ctx => rdr.readTerm()(ctx))

      def localCtx = localContext(sym)

      def ValDef(tpt: Tree) =
        ta.assignType(untpd.ValDef(sym.name.asTermName, tpt, readRhs(localCtx)), sym)

      def DefDef(tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree) =
         ta.assignType(
            untpd.DefDef(
              sym.name.asTermName, tparams, vparamss, tpt, readRhs(localCtx)),
            sym)

      def TypeDef(rhs: Tree) =
        ta.assignType(untpd.TypeDef(sym.name.asTypeName, rhs), sym)

      def ta =  ctx.typeAssigner

      val name = readName()
      pickling.println(s"reading def of $name at $start")
      val tree: MemberDef = tag match {
        case DEFDEF =>
          val tparams = readParams[TypeDef](TYPEPARAM)(localCtx)
          val vparamss = readParamss(localCtx)
          val tpt = readTpt()
          val typeParams = tparams.map(_.symbol)
          val valueParamss = ctx.normalizeIfConstructor(
              vparamss.nestedMap(_.symbol), name == nme.CONSTRUCTOR)
          val resType = ctx.effectiveResultType(sym, typeParams, tpt.tpe)
          sym.info = ctx.methodType(typeParams, valueParamss, resType)
          if (sym.isSetter && sym.accessedFieldOrGetter.is(ParamAccessor)) {
            // reconstitute ParamAccessor flag of setters for var parameters, which is not pickled
            sym.setFlag(ParamAccessor)
            sym.resetFlag(Deferred)
          }
          DefDef(tparams, vparamss, tpt)
        case VALDEF =>
          val tpt = readTpt()
          sym.info = tpt.tpe
          ValDef(tpt)
        case TYPEDEF | TYPEPARAM =>
          if (sym.isClass) {
            val companion = sym.scalacLinkedClass

            // Is the companion defined in the same Tasty file as `sym`?
            // The only case to check here is if `sym` is a root. In this case
            // `companion` might have been entered by the environment but it might
            // be missing from the Tasty file. So we check explicitly for that.
            def isCodefined =
              roots.contains(companion.denot) == seenRoots.contains(companion)
            if (companion.exists && isCodefined) {
              import transform.SymUtils._
              if (sym is Flags.ModuleClass) sym.registerCompanionMethod(nme.COMPANION_CLASS_METHOD, companion)
              else sym.registerCompanionMethod(nme.COMPANION_MODULE_METHOD, companion)
            }
            TypeDef(readTemplate(localCtx))
          } else {
            val rhs = readTpt()
            sym.info = rhs.tpe match {
              case _: TypeBounds | _: ClassInfo => rhs.tpe
              case _ => TypeAlias(rhs.tpe, sym.variance)
            }
            TypeDef(rhs)
          }
        case PARAM =>
          val tpt = readTpt()
          if (noRhs(end)) {
            sym.info = tpt.tpe
            ValDef(tpt)
          }
          else {
            sym.setFlag(Method)
            sym.info = ExprType(tpt.tpe)
            pickling.println(i"reading param alias $name -> $currentAddr")
            DefDef(Nil, Nil, tpt)
          }
      }
      val mods =
        if (sym.annotations.isEmpty) untpd.EmptyModifiers
        else untpd.Modifiers(annotations = sym.annotations.map(_.tree))
      tree.withMods(mods)
        // record annotations in tree so that tree positions can be filled in.
        // Note: Once the inline PR with its changes to positions is in, this should be
        // no longer necessary.
      goto(end)
      setPos(start, tree)
      if (!sym.isType) { // Only terms might have leaky aliases, see the documentation of `checkNoPrivateLeaks`
        sym.info = ta.avoidPrivateLeaks(sym, tree.pos)
      }
      tree
    }

    private def readTemplate(implicit ctx: Context): Template = {
      val start = currentAddr
      val cls = ctx.owner.asClass
      def setClsInfo(parents: List[TypeRef], selfType: Type) =
        cls.info = ClassInfo(cls.owner.thisType, cls, parents, cls.unforcedDecls, selfType)
      val assumedSelfType =
        if (cls.is(Module) && cls.owner.isClass)
          TermRef.withSig(cls.owner.thisType, cls.name.sourceModuleName, Signature.NotAMethod)
        else NoType
      setClsInfo(Nil, assumedSelfType)
      val localDummy = symbolAtCurrent()
      assert(readByte() == TEMPLATE)
      val end = readEnd()
      val tparams = readIndexedParams[TypeDef](TYPEPARAM)
      val vparams = readIndexedParams[ValDef](PARAM)
      val parents = collectWhile(nextByte != SELFDEF && nextByte != DEFDEF) {
        nextByte match {
          case APPLY | TYPEAPPLY => readTerm()
          case _ => readTpt()
        }
      }
      val parentRefs = ctx.normalizeToClassRefs(parents.map(_.tpe), cls, cls.unforcedDecls)
      val self =
        if (nextByte == SELFDEF) {
          readByte()
          untpd.ValDef(readName(), readTpt(), EmptyTree).withType(NoType)
        }
        else EmptyValDef
      setClsInfo(parentRefs, if (self.isEmpty) NoType else self.tpt.tpe)
      cls.setNoInitsFlags(fork.indexStats(end))
      val constr = readIndexedDef().asInstanceOf[DefDef]

      def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree])(implicit ctx: Context): (List[Tree], List[Tree]) =
        (tparams, stats) match {
          case (tparam :: tparams1, (alias: TypeDef) :: stats1)
          if tparam.name == alias.name.expandedName(cls) =>
            val (tas, stats2) = mergeTypeParamsAndAliases(tparams1, stats1)
            (tparam :: alias :: tas, stats2)
          case _ =>
            (tparams, stats)
        }

      val lazyStats = readLater(end, rdr => implicit ctx => {
        val stats0 = rdr.readIndexedStats(localDummy, end)
        val (tparamsAndAliases, stats) = mergeTypeParamsAndAliases(tparams, stats0)
        tparamsAndAliases ++ vparams ++ stats
      })
      setPos(start,
        untpd.Template(constr, parents, self, lazyStats)
          .withType(localDummy.nonMemberTermRef))
    }

    def skipToplevel()(implicit ctx: Context): Unit= {
      if (!isAtEnd)
        nextByte match {
          case IMPORT | PACKAGE =>
            skipTree()
            skipToplevel()
          case _ =>
        }
    }

    def readTopLevel()(implicit ctx: Context): List[Tree] = {
      @tailrec def read(acc: ListBuffer[Tree]): List[Tree] = nextByte match {
        case IMPORT | PACKAGE =>
          acc += readIndexedStat(NoSymbol)
          if (!isAtEnd) read(acc) else acc.toList
        case _ => // top-level trees which are not imports or packages are not part of tree
          acc.toList
      }
      read(new ListBuffer[tpd.Tree])
    }

    def readIndexedStat(exprOwner: Symbol)(implicit ctx: Context): Tree = nextByte match {
      case TYPEDEF | VALDEF | DEFDEF =>
        readIndexedDef()
      case IMPORT =>
        readImport()
      case PACKAGE =>
        val start = currentAddr
        processPackage { (pid, end) => implicit ctx =>
          setPos(start, PackageDef(pid, readIndexedStats(exprOwner, end)(ctx)))
        }
      case _ =>
        readTerm()(ctx.withOwner(exprOwner))
    }

    def readImport()(implicit ctx: Context): Tree = {
      val start = currentAddr
      readByte()
      readEnd()
      val expr = readTerm()
      def readSelectors(): List[untpd.Tree] = nextByte match {
        case IMPORTED =>
          val start = currentAddr
          readByte()
          val from = setPos(start, untpd.Ident(readName()))
          nextByte match {
            case RENAMED =>
              val start2 = currentAddr
              readByte()
              val to = setPos(start2, untpd.Ident(readName()))
              untpd.Thicket(from, to) :: readSelectors()
            case _ =>
              from :: readSelectors()
          }
          case _ =>
            Nil
      }
      setPos(start, Import(expr, readSelectors()))
    }

    def readIndexedStats(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[Tree] =
      until(end)(readIndexedStat(exprOwner))

    def readStats(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[Tree] = {
      fork.indexStats(end)
      readIndexedStats(exprOwner, end)
    }

    def readIndexedParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] =
      collectWhile(nextByte == tag) { readIndexedDef().asInstanceOf[T] }

    def readParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = {
      fork.indexParams(tag)
      readIndexedParams(tag)
    }

// ------ Reading trees -----------------------------------------------------

    def readTerm()(implicit ctx: Context): Tree = {  // TODO: rename to readTree
      val start = currentAddr
      val tag = readByte()
      pickling.println(s"reading term ${astTagToString(tag)} at $start")

      def readPathTerm(): Tree = {
        goto(start)
        readType() match {
          case path: TypeRef => TypeTree(path)
          case path: TermRef => ref(path)
          case path: ThisType => untpd.This(untpd.EmptyTypeIdent).withType(path)
          case path: ConstantType => Literal(path.value)
        }
      }

      def completeSelect(name: Name, tpf: Type => Type): Select = {
        val localCtx =
          if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx
        val qual = readTerm()(localCtx)
        val unshadowed = name.exclude(ShadowedName)
        untpd.Select(qual, unshadowed).withType(tpf(qual.tpe.widenIfUnstable))
      }

      def readQualId(): (untpd.Ident, TypeRef) = {
        val qual = readTerm().asInstanceOf[untpd.Ident]
         (untpd.Ident(qual.name).withPos(qual.pos), qual.tpe.asInstanceOf[TypeRef])
      }

      def readSimpleTerm(): Tree = tag match {
        case SHARED =>
          forkAt(readAddr()).readTerm()
        case IDENT =>
          untpd.Ident(readName()).withType(readType())
        case IDENTtpt =>
          untpd.Ident(readName().toTypeName).withType(readType())
        case SELECT =>
          def readRest(name: Name, sig: Signature) =
            completeSelect(name, TermRef.withSig(_, name.asTermName, sig))
          readName() match {
            case SignedName(name, sig) => readRest(name, sig)
            case name => readRest(name, Signature.NotAMethod)
          }
        case SELECTtpt =>
          val name = readName().toTypeName
          completeSelect(name, TypeRef(_, name))
        case QUALTHIS =>
          val (qual, tref) = readQualId()
          untpd.This(qual).withType(ThisType.raw(tref))
        case NEW =>
          New(readTpt())
        case SINGLETONtpt =>
          SingletonTypeTree(readTerm())
        case BYNAMEtpt =>
          ByNameTypeTree(readTpt())
        case _ =>
          readPathTerm()
      }

      def readLengthTerm(): Tree = {
        val end = readEnd()

        def localNonClassCtx = {
          val ctx1 = ctx.fresh.setNewScope
          if (ctx.owner.isClass) ctx1.setOwner(ctx1.newLocalDummy(ctx.owner)) else ctx1
        }

        def readBlock(mkTree: (List[Tree], Tree) => Tree): Tree = {
          val exprReader = fork
          skipTree()
          val localCtx = localNonClassCtx
          val stats = readStats(ctx.owner, end)(localCtx)
          val expr = exprReader.readTerm()(localCtx)
          mkTree(stats, expr)
        }

        val result =
          (tag: @switch) match {
            case SUPER =>
              val qual = readTerm()
              val (mixId, mixTpe) = ifBefore(end)(readQualId(), (untpd.EmptyTypeIdent, NoType))
              tpd.Super(qual, mixId, ctx.mode.is(Mode.InSuperCall), mixTpe.typeSymbol)
            case APPLY =>
              val fn = readTerm()
              val isJava = fn.symbol.is(JavaDefined)
              def readArg() = readTerm() match {
                case SeqLiteral(elems, elemtpt) if isJava =>
                  JavaSeqLiteral(elems, elemtpt)
                case arg => arg
              }
              tpd.Apply(fn, until(end)(readArg()))
            case TYPEAPPLY =>
              tpd.TypeApply(readTerm(), until(end)(readTpt()))
            case TYPED =>
              val expr = readTerm()
              val tpt = readTpt()
              val expr1 = expr match {
                case SeqLiteral(elems, elemtpt) if tpt.tpe.isRef(defn.ArrayClass) =>
                  JavaSeqLiteral(elems, elemtpt)
                case expr => expr
              }
              Typed(expr1, tpt)
            case NAMEDARG =>
              NamedArg(readName(), readTerm())
            case ASSIGN =>
              Assign(readTerm(), readTerm())
            case BLOCK =>
              readBlock(Block)
            case INLINED =>
              val call = readTerm()
              readBlock((defs, expr) => Inlined(call, defs.asInstanceOf[List[MemberDef]], expr))
            case IF =>
              If(readTerm(), readTerm(), readTerm())
            case LAMBDA =>
              val meth = readTerm()
              val tpt = ifBefore(end)(readTpt(), EmptyTree)
              Closure(Nil, meth, tpt)
            case MATCH =>
              Match(readTerm(), readCases(end))
            case RETURN =>
              val from = readSymRef()
              val expr = ifBefore(end)(readTerm(), EmptyTree)
              Return(expr, Ident(from.termRef))
            case TRY =>
              Try(readTerm(), readCases(end), ifBefore(end)(readTerm(), EmptyTree))
            case REPEATED =>
              val elemtpt = readTpt()
              SeqLiteral(until(end)(readTerm()), elemtpt)
            case BIND =>
              val name = readName()
              val info = readType()
              val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, info)
              registerSym(start, sym)
              Bind(sym, readTerm())
            case ALTERNATIVE =>
              Alternative(until(end)(readTerm()))
            case UNAPPLY =>
              val fn = readTerm()
              val implicitArgs =
                collectWhile(nextByte == IMPLICITarg) {
                  readByte()
                  readTerm()
                }
              val patType = readType()
              val argPats = until(end)(readTerm())
              UnApply(fn, implicitArgs, argPats, patType)
            case REFINEDtpt =>
              val refineCls = ctx.newCompleteClassSymbol(
                ctx.owner, tpnme.REFINE_CLASS, Fresh, parents = Nil)
              typeAtAddr(start) = refineCls.typeRef
              val parent = readTpt()
              val refinements = readStats(refineCls, end)(localContext(refineCls))
              RefinedTypeTree(parent, refinements, refineCls)
            case APPLIEDtpt =>
              AppliedTypeTree(readTpt(), until(end)(readTpt()))
            case ANDtpt =>
              val tpt1 = readTpt()
              val tpt2 = readTpt()
              // FIXME: We need to do this instead of "AndType(tpt1, tpt2)" to avoid self-type cyclic reference in tasty_tools
              untpd.AndTypeTree(tpt1, tpt2).withType(AndType(tpt1.tpe, tpt2.tpe))
            case ORtpt =>
              OrTypeTree(readTpt(), readTpt())
            case ANNOTATEDtpt =>
              Annotated(readTpt(), readTerm())
            case LAMBDAtpt =>
              val localCtx = localNonClassCtx
              val tparams = readParams[TypeDef](TYPEPARAM)(localCtx)
              val body = readTpt()(localCtx)
              LambdaTypeTree(tparams, body)
            case TYPEBOUNDStpt =>
              TypeBoundsTree(readTpt(), readTpt())
            case _ =>
              readPathTerm()
          }
        assert(currentAddr == end, s"$start $currentAddr $end ${astTagToString(tag)}")
        result
      }

      val tree = if (tag < firstLengthTreeTag) readSimpleTerm() else readLengthTerm()
      if (!tree.isInstanceOf[TypTree]) // FIXME: Necessary to avoid self-type cyclic reference in tasty_tools
        tree.overwriteType(tree.tpe.simplified)
      setPos(start, tree)
    }

    def readTpt()(implicit ctx: Context) =
      if (isTypeTreeTag(nextUnsharedTag)) readTerm()
      else {
        val start = currentAddr
        val tp = readType()
        if (tp.exists) setPos(start, TypeTree(tp)) else EmptyTree
      }

    def readCases(end: Addr)(implicit ctx: Context): List[CaseDef] =
      collectWhile((nextByte == CASEDEF || nextByte == SHARED) && currentAddr != end) {
        if (nextByte == SHARED) {
          readByte()
          forkAt(readAddr()).readCase()(ctx.fresh.setNewScope)
        }
        else readCase()(ctx.fresh.setNewScope)
      }

    def readCase()(implicit ctx: Context): CaseDef = {
      val start = currentAddr
      readByte()
      val end = readEnd()
      val pat = readTerm()
      val rhs = readTerm()
      val guard = ifBefore(end)(readTerm(), EmptyTree)
      setPos(start, CaseDef(pat, guard, rhs))
    }

    def readLater[T <: AnyRef](end: Addr, op: TreeReader => Context => T): Trees.Lazy[T] = {
      val localReader = fork
      goto(end)
      new LazyReader(localReader, op)
    }

// ------ Setting positions ------------------------------------------------

    /** Set position of `tree` at given `addr`. */
    def setPos[T <: untpd.Tree](addr: Addr, tree: T)(implicit ctx: Context): tree.type =
      if (ctx.mode.is(Mode.ReadPositions)) {
        posUnpicklerOpt match {
          case Some(posUnpickler) =>
            //println(i"setPos $tree / ${tree.getClass} at $addr to ${posUnpickler.posAt(addr)}")
            val pos = posUnpickler.posAt(addr)
            if (pos.exists) tree.setPosUnchecked(pos)
            tree
          case _  =>
            //println(i"no pos $tree")
            tree
        }
      }
      else tree
  }

  class LazyReader[T <: AnyRef](reader: TreeReader, op: TreeReader => Context => T) extends Trees.Lazy[T] {
    def complete(implicit ctx: Context): T = {
      pickling.println(i"starting to read at ${reader.reader.currentAddr}")
      op(reader)(ctx.addMode(Mode.AllowDependentFunctions).withPhaseNoLater(ctx.picklerPhase))
    }
  }

  /** A lazy datastructure that records how definitions are nested in TASTY data.
   *  The structure is lazy because it needs to be computed only for forward references
   *  to symbols that happen before the referenced symbol is created (see `symbolAt`).
   *  Such forward references are rare.
   *
   *  @param   addr    The address of tree representing an owning definition, NoAddr for root tree
   *  @param   tag     The tag at `addr`. Used to determine which subtrees to scan for children
   *                   (i.e. if `tag` is template, don't scan member defs, as these belong already
   *                    to enclosing class).
   *  @param   reader  The reader to be used for scanning for children
   *  @param   end     The end of the owning definition
   */
  class OwnerTree(val addr: Addr, tag: Int, reader: TreeReader, val end: Addr) {

    /** All definitions that have the definition at `addr` as closest enclosing definition */
    lazy val children: List[OwnerTree] = {
      val buf = new ListBuffer[OwnerTree]
      reader.scanTrees(buf, end, if (tag == TEMPLATE) NoMemberDefs else AllDefs)
      buf.toList
    }

    /** Find the owner of definition at `addr` */
    def findOwner(addr: Addr)(implicit ctx: Context): Symbol = {
      def search(cs: List[OwnerTree], current: Symbol): Symbol =
        try cs match {
        case ot :: cs1 =>
          if (ot.addr.index == addr.index)
            current
          else if (ot.addr.index < addr.index && addr.index < ot.end.index)
            search(ot.children, reader.symbolAt(ot.addr))
          else
            search(cs1, current)
        case Nil =>
          throw new TreeWithoutOwner
      }
      catch {
        case ex: TreeWithoutOwner =>
          println(i"no owner for $addr among $cs")  // DEBUG
          throw ex
      }
      search(children, NoSymbol)
    }

    override def toString = s"OwnerTree(${addr.index}, ${end.index}"
  }
}

object TreeUnpickler {

  /** An enumeration indicating which subtrees should be added to an OwnerTree. */
  type MemberDefMode = Int
  final val MemberDefsOnly = 0   // add only member defs; skip other statements
  final val NoMemberDefs = 1     // add only statements that are not member defs
  final val AllDefs = 2          // add everything

  class TreeWithoutOwner extends Exception
}