aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
blob: 111a5f5f518aa53978b04a4359749804edb5862f (plain) (tree)
1
2
3
4
5
6
7
8
9




                                                   
                                          
                                         

                                            




                                              
                                                                 















                                                                   
                                                                              

















                                             
                                  














                                        
                                           

                                        
                                   
                                    































                                                                               
                                    


                                              

                                               













                                                         




                                                                                                
                                                                                                                                      
                                                                                            
                                                                                                                                    
                                                                                                  
                                                                                                                                  






                                                                                                   



                                                                                                                           




                                                                                                                                                                               



                                                                 
                                             
                                                                                              


                                                                     
                                                                     






























                                                                                                      
                                                                                  

























                                                                                                                                                                       


                                                                                          









                                                                       
                                   



                                     

                                      










                                                                            
                                                                                      



























                                                                                                   
                                                                              





                                                   


                                                                                                                                     


                    



















                                                                    













                                                                     
                                                                                       
 
                                                                                                            






































































                                                                                    
                                                                                         










                                                                                                                


                                                                     













                                                                                            
                                                                                   




                                                                                            
                                                                                                     

                                                   
                                    
                                                                                                                              



                                                                                  
                                             


                                                                                                                                 







                                                                                         
                                                                                          





                                                                                             
                                                                           
 
                                                                     




                                                                                                     
                                                                            




                                                                           

                                          

                                 







                                                              



                                                                                      


                                                                                 

                                                                                               




                                                                                                           



              













                                                                                                                 

 


                                                                                                            
 

                                                                
 


                                                                                                          
 
                                             




                                                                                                
                                                                           




                                                                                                     
                                                                          









                                                                                                     
                                                       

 
                                                     

   





















                                                                                                                                     
                                                       










































                                                                                                                                                                                        


                                                       
















































































                                                                                                                                                                                  
                         


                                           









                                                                             


                                       
                           


                                         
                        



                                                    
                        


                                           
                        


                                                       
                         
   
 
                                                 
                         





                                                             
                             




                                              








                                                                                   










                                                     






                                                                                            



















































                                                       







                                                                         



                                                                                         



       
                                       
 
package dotty.tools.backend.jvm

import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc
import dotty.tools.dotc.backend.jvm.DottyPrimitives
import dotty.tools.dotc.core.Flags.FlagSet
import dotty.tools.dotc.transform.Erasure
import dotty.tools.dotc.transform.SymUtils._
import java.io.{File => JFile}

import scala.collection.generic.Clearable
import scala.collection.mutable
import scala.reflect.ClassTag
import scala.reflect.internal.util.WeakHashSet
import scala.reflect.io.{Directory, PlainDirectory, AbstractFile}
import scala.tools.asm.{ClassVisitor, FieldVisitor, MethodVisitor}
import scala.tools.nsc.backend.jvm.{BCodeHelpers, BackendInterface}
import dotty.tools.dotc.core._
import Periods._
import SymDenotations._
import Contexts._
import Types._
import Symbols._
import Denotations._
import Phases._
import java.lang.AssertionError
import dotty.tools.dotc.util.{Positions, DotClass}
import Decorators._
import tpd._
import StdNames.nme

class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
  trait NonExistentTree extends tpd.Tree
  type Symbol          = Symbols.Symbol
  type Type            = Types.Type
  type Tree            = tpd.Tree
  type CompilationUnit = dotc.CompilationUnit
  type Constant        = Constants.Constant
  type Literal         = tpd.Literal
  type Position        = Positions.Position
  type Name            = Names.Name
  type ClassDef        = tpd.TypeDef
  type TypeDef         = tpd.TypeDef
  type Apply           = tpd.Apply
  type TypeApply       = tpd.TypeApply
  type Try             = tpd.Try
  type Assign          = tpd.Assign
  type Ident           = tpd.Ident
  type If              = tpd.If
  type ValDef          = tpd.ValDef
  type Throw           = tpd.Apply
  type Return          = tpd.Return
  type Block           = tpd.Block
  type Typed           = tpd.Typed
  type Match           = tpd.Match
  type This            = tpd.This
  type CaseDef         = tpd.CaseDef
  type Alternative     = tpd.Alternative
  type DefDef          = tpd.DefDef
  type Template        = tpd.Template
  type Select          = tpd.Select
  type Bind            = tpd.Bind
  type New             = tpd.New
  type Super           = tpd.Super
  type Modifiers       = tpd.Modifiers
  type Annotation      = NonExistentTree
  type ArrayValue      = tpd.JavaSeqLiteral
  type ApplyDynamic    = NonExistentTree
  type ModuleDef       = NonExistentTree
  type LabelDef        = tpd.DefDef
  type Closure         = tpd.Closure

  val NoSymbol = Symbols.NoSymbol
  val NoPosition: Position = Positions.NoPosition
  val EmptyTree: Tree = tpd.EmptyTree


  val UnitTag: ConstantTag = Constants.UnitTag
  val IntTag: ConstantTag = Constants.IntTag
  val FloatTag: ConstantTag = Constants.FloatTag
  val NullTag: ConstantTag = Constants.NullTag
  val BooleanTag: ConstantTag = Constants.BooleanTag
  val ByteTag: ConstantTag = Constants.ByteTag
  val ShortTag: ConstantTag = Constants.ShortTag
  val CharTag: ConstantTag = Constants.CharTag
  val DoubleTag: ConstantTag = Constants.DoubleTag
  val LongTag: ConstantTag = Constants.LongTag
  val StringTag: ConstantTag = Constants.StringTag
  val ClazzTag: ConstantTag = Constants.ClazzTag
  val EnumTag: ConstantTag = Constants.EnumTag

  val nme_This: Name = StdNames.nme.This
  val nme_EMPTY_PACKAGE_NAME: Name = StdNames.nme.EMPTY_PACKAGE
  val nme_CONSTRUCTOR: Name = StdNames.nme.CONSTRUCTOR
  val nme_WILDCARD: Name = StdNames.nme.WILDCARD
  val nme_THIS: Name = StdNames.nme.THIS
  val nme_PACKAGE: Name = StdNames.nme.PACKAGE
  val nme_EQEQ_LOCAL_VAR: Name = StdNames.nme.EQEQ_LOCAL_VAR

  val BoxesRunTimeModule     = ctx.requiredModule("scala.runtime.BoxesRunTime")
  val BoxesRunTimeClass      = toDenot(BoxesRunTimeModule).moduleClass.asClass

  val nme_valueOf: Name = StdNames.nme.valueOf
  val nme_apply = StdNames.nme.apply
  val NothingClass: Symbol = defn.NothingClass
  val NullClass: Symbol = defn.NullClass
  val ObjectClass: Symbol = defn.ObjectClass
  val Object_Type: Type = defn.ObjectType
  val Throwable_Type: Type = defn.ThrowableType
  val Object_isInstanceOf: Symbol = defn.Any_isInstanceOf
  val Object_asInstanceOf: Symbol = defn.Any_asInstanceOf
  val Object_equals: Symbol = defn.Any_equals
  val ArrayClass: Symbol = defn.ArrayClass
  val UnitClass: Symbol = defn.UnitClass
  val BooleanClass: Symbol = defn.BooleanClass
  val CharClass: Symbol = defn.CharClass
  val ShortClass: Symbol = defn.ShortClass
  val ClassClass: Symbol = defn.ClassClass
  val ByteClass: Symbol = defn.ByteClass
  val IntClass: Symbol = defn.IntClass
  val LongClass: Symbol = defn.LongClass
  val FloatClass: Symbol = defn.FloatClass
  val DoubleClass: Symbol = defn.DoubleClass
  def isArrayClone(tree: Tree) = tree match {
    case Select(qual, StdNames.nme.clone_) if qual.tpe.widen.isInstanceOf[JavaArrayType] => true
    case _ => false
  }

  val hashMethodSym: Symbol = NoSymbol // used to dispatch ## on primitives to ScalaRuntime.hash. Should be implemented by a miniphase
  val externalEqualsNumNum: Symbol = ctx.requiredMethod(BoxesRunTimeClass, nme.equalsNumNum)
  lazy val externalEqualsNumChar: Symbol = ??? // ctx.requiredMethod(BoxesRunTimeClass, nme.equalsNumChar) // this method is private
  val externalEqualsNumObject: Symbol = ctx.requiredMethod(BoxesRunTimeClass, nme.equalsNumObject)
  val externalEquals: Symbol = BoxesRunTimeClass.info.decl(nme.equals_).suchThat(toDenot(_).info.firstParamTypes.size == 2).symbol
  val MaxFunctionArity: Int = Definitions.MaxFunctionArity
  val FunctionClass: Array[Symbol] = defn.FunctionClass.asInstanceOf[Array[Symbol]]
  val AbstractFunctionClass: Array[Symbol] = defn.AbstractFunctionClass.asInstanceOf[Array[Symbol]]
  val PartialFunctionClass: Symbol = defn.PartialFunctionClass
  val AbstractPartialFunctionClass: Symbol = defn.AbstractPartialFunctionClass
  val String_valueOf: Symbol = defn.String_valueOf_Object

  def boxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses.map{x =>
    (x, Erasure.Boxing.boxMethod(x.asClass))
  }.toMap
  def unboxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses.map(x => (x, Erasure.Boxing.unboxMethod(x.asClass))).toMap

  private val mkArrayNames: Set[String] = Set("Byte", "Float", "Char", "Double", "Boolean", "Unit", "Long", "Int", "Short", "Ref")

  override lazy val syntheticArrayConstructors: Set[Symbol] = mkArrayNames.map(nm => ctx.requiredMethod(toDenot(defn.DottyArraysModule).moduleClass.asClass, s"new${nm}Array"))

  def isBox(sym: Symbol): Boolean = Erasure.Boxing.isBox(sym)
  def isUnbox(sym: Symbol): Boolean = Erasure.Boxing.isUnbox(sym)

  val primitives: Primitives = new Primitives {
    val primitives = new DottyPrimitives(ctx)
    def getPrimitive(app: Apply, reciever: Type): Int = primitives.getPrimitive(app, reciever)

    def getPrimitive(sym: Symbol): Int = primitives.getPrimitive(sym)

    def isPrimitive(fun: Tree): Boolean = primitives.isPrimitive(fun)
  }
  implicit val TypeDefTag: ClassTag[TypeDef] = ClassTag[TypeDef](classOf[TypeDef])
  implicit val ApplyTag: ClassTag[Apply] = ClassTag[Apply](classOf[Apply])
  implicit val SelectTag: ClassTag[Select] = ClassTag[Select](classOf[Select])
  implicit val TypeApplyTag: ClassTag[TypeApply] = ClassTag[TypeApply](classOf[TypeApply])
  implicit val ClassDefTag: ClassTag[ClassDef] = ClassTag[TypeDef](classOf[TypeDef])
  implicit val TryTag: ClassTag[Try] = ClassTag[Try](classOf[Try])
  implicit val AssignTag: ClassTag[Assign] = ClassTag[Assign](classOf[Assign])
  implicit val IdentTag: ClassTag[Ident] = ClassTag[Ident](classOf[Ident])
  implicit val IfTag: ClassTag[If] = ClassTag[If](classOf[If])
  implicit val LabelDefTag: ClassTag[LabelDef] = ClassTag[LabelDef](classOf[LabelDef])
  implicit val ValDefTag: ClassTag[ValDef] = ClassTag[ValDef](classOf[ValDef])
  implicit val ThrowTag: ClassTag[Throw] = ClassTag[Throw](classOf[Throw])
  implicit val ReturnTag: ClassTag[Return] = ClassTag[Return](classOf[Return])
  implicit val LiteralTag: ClassTag[Literal] = ClassTag[Literal](classOf[Literal])
  implicit val BlockTag: ClassTag[Block] = ClassTag[Block](classOf[Block])
  implicit val TypedTag: ClassTag[Typed] = ClassTag[Typed](classOf[Typed])
  implicit val ArrayValueTag: ClassTag[ArrayValue] = ClassTag[ArrayValue](classOf[ArrayValue])
  implicit val MatchTag: ClassTag[Match] = ClassTag[Match](classOf[Match])
  implicit val CaseDefTag: ClassTag[CaseDef] = ClassTag[CaseDef](classOf[CaseDef])
  implicit val ThisTag: ClassTag[This] = ClassTag[This](classOf[This])
  implicit val AlternativeTag: ClassTag[Alternative] = ClassTag[Alternative](classOf[Alternative])
  implicit val DefDefTag: ClassTag[DefDef] = ClassTag[DefDef](classOf[DefDef])
  implicit val ModuleDefTag: ClassTag[ModuleDef] = ClassTag[ModuleDef](classOf[ModuleDef])
  implicit val NameTag: ClassTag[Name] = ClassTag[Name](classOf[Name])
  implicit val TemplateTag: ClassTag[Template] = ClassTag[Template](classOf[Template])
  implicit val BindTag: ClassTag[Bind] = ClassTag[Bind](classOf[Bind])
  implicit val NewTag: ClassTag[New] = ClassTag[New](classOf[New])
  implicit val ApplyDynamicTag: ClassTag[ApplyDynamic] = ClassTag[ApplyDynamic](classOf[ApplyDynamic])
  implicit val SuperTag: ClassTag[Super] = ClassTag[Super](classOf[Super])
  implicit val ConstantClassTag: ClassTag[Constant] = ClassTag[Constant](classOf[Constant])
  implicit val ClosureTag: ClassTag[Closure] = ClassTag[Closure](classOf[Closure])

  /* dont emit any annotations for now*/
  def isRuntimeVisible(annot: Annotation): Boolean = false
  def shouldEmitAnnotation(annot: Annotation): Boolean = false

  def emitAnnotations(cw: ClassVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
  def emitAnnotations(mw: MethodVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
  def emitAnnotations(fw: FieldVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
  def emitParamAnnotations(jmethod: MethodVisitor, pannotss: List[List[Annotation]], bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = ()
  def getAnnotPickle(jclassName: String, sym: Symbol): Option[Annotation] = None


  def getRequiredClass(fullname: String): Symbol = ctx.requiredClass(fullname.toTermName)

  def getClassIfDefined(fullname: String): Symbol = NoSymbol // used only for android. todo: implement

  private def erasureString(clazz: Class[_]): String = {
    if (clazz.isArray) "Array[" + erasureString(clazz.getComponentType) + "]"
    else clazz.getName
  }

  def requiredClass[T](implicit evidence: ClassTag[T]): Symbol = {
    ctx.requiredClass(erasureString(evidence.runtimeClass).toTermName)
  }

  def requiredModule[T](implicit evidence: ClassTag[T]): Symbol = {
    val moduleName = erasureString(evidence.runtimeClass)
    val className = if (moduleName.endsWith("$")) moduleName.dropRight(1)  else moduleName
    ctx.requiredModule(className.toTermName)
  }


  def debuglog(msg: => String): Unit = ctx.debuglog(msg)
  def informProgress(msg: String): Unit = ctx.informProgress(msg)
  def log(msg: => String): Unit = ctx.log(msg)
  def error(pos: Position, msg: String): Unit = ctx.error(msg, pos)
  def warning(pos: Position, msg: String): Unit = ctx.warning(msg, pos)
  def abort(msg: String): Nothing = {
    ctx.error(msg)
    throw new RuntimeException(msg)
  }

  def emitAsmp: Option[String] = None

  def shouldEmitJumpAfterLabels = true

  def dumpClasses: Option[String] =
    if(ctx.settings.Ydumpclasses.isDefault) None
    else Some(ctx.settings.Ydumpclasses.value)

  def mainClass: Option[String] =
    if (ctx.settings.mainClass.isDefault) None
    else Some(ctx.settings.mainClass.value)
  def setMainClass(name: String): Unit = ctx.settings.mainClass.update(name)


  def noForwarders: Boolean = ctx.settings.noForwarders.value
  def debuglevel: Int = 3 // 0 -> no debug info; 1-> filename; 2-> lines; 3-> varnames
  def settings_debug: Boolean = ctx.settings.debug.value
  def targetPlatform: String = ctx.settings.target.value

  val perRunCaches: Caches = new Caches {
    def newAnyRefMap[K <: AnyRef, V](): mutable.AnyRefMap[K, V] = new mutable.AnyRefMap[K, V]()
    def newWeakMap[K, V](): mutable.WeakHashMap[K, V] = new mutable.WeakHashMap[K, V]()
    def recordCache[T <: Clearable](cache: T): T = cache
    def newWeakSet[K <: AnyRef](): WeakHashSet[K] = new WeakHashSet[K]()
    def newMap[K, V](): mutable.HashMap[K, V] = new mutable.HashMap[K, V]()
    def newSet[K](): mutable.Set[K] = new mutable.HashSet[K]
  }



  val MODULE_INSTANCE_FIELD: String = nme.MODULE_INSTANCE_FIELD.toString

  def internalNameString(offset: Int, length: Int): String = new String(Names.chrs, offset, length)

  def newTermName(prefix: String): Name = prefix.toTermName

  val Flag_SYNTHETIC: Flags = Flags.Synthetic.bits
  val Flag_METHOD: Flags = Flags.Method.bits
  val ExcludedForwarderFlags: Flags = {
      Flags.Specialized | Flags.Lifted | Flags.Protected | Flags.JavaStatic |
     Flags.ExpandedName | Flags.Bridge | Flags.VBridge | Flags.Private | Flags.Macro
  }.bits


  def isQualifierSafeToElide(qual: Tree): Boolean = tpd.isIdempotentExpr(qual)
  def desugarIdent(i: Ident): Option[Select] = {
    i.tpe match {
      case TermRef(prefix: TermRef, name) =>
        Some(tpd.ref(prefix).select(i.symbol))
      case TermRef(prefix: ThisType, name) =>
        Some(tpd.This(prefix.cls).select(i.symbol))
      case TermRef(NoPrefix, name) =>
        if(i.symbol is Flags.Method) Some(This(i.symbol.enclosingClass).select(i.symbol)) // workaround #342 todo: remove after fixed
        else None
      case _ => None
    }
  }
  def getLabelDefOwners(tree: Tree): Map[Tree, List[LabelDef]] = {
    // for each rhs of a defdef returns LabelDefs inside this DefDef
    val res = new collection.mutable.HashMap[Tree, List[LabelDef]]()

    val t = new TreeTraverser {
      var outerRhs: Tree = tree

      def traverse(tree: tpd.Tree): Unit = tree match {
        case t: DefDef =>
          if (t.symbol is Flags.Label)
            res.put(outerRhs, t :: res.getOrElse(outerRhs, Nil))
          else outerRhs = t
          traverseChildren(t)
        case _ => traverseChildren(tree)
      }
    }

    t.traverse(tree)
    res.toMap
  }

  // todo: remove
  def isMaybeBoxed(sym: Symbol) = {
    (sym == ObjectClass) ||
      (sym == JavaSerializableClass) ||
      (sym == defn.ComparableClass) ||
      (sym derivesFrom BoxedNumberClass) ||
      (sym derivesFrom BoxedCharacterClass) ||
      (sym derivesFrom BoxedBooleanClass)
  }

  def getSingleOutput: Option[AbstractFile] = None // todo: implement


  def getGenericSignature(sym: Symbol, owner: Symbol): String = null // todo: implement

  def getStaticForwarderGenericSignature(sym: Symbol, moduleClass: Symbol): String = null // todo: implement


  def sourceFileFor(cu: CompilationUnit): String = cu.source.file.name



  implicit def positionHelper(a: Position): PositionHelper = new PositionHelper {
    def isDefined: Boolean = a.exists
    def line: Int = sourcePos(a).line
    def finalPosition: Position = a
  }

  implicit def constantHelper(a: Constant): ConstantHelper = new ConstantHelper {
    def booleanValue: Boolean = a.booleanValue
    def longValue: Long = a.longValue
    def byteValue: Byte = a.byteValue
    def stringValue: String = a.stringValue
    def symbolValue: Symbol = a.symbolValue
    def floatValue: Float = a.floatValue
    def value: Any = a.value
    def tag: ConstantTag = a.tag
    def typeValue: Type = a.typeValue
    def shortValue: Short = a.shortValue
    def intValue: Int = a.intValue
    def doubleValue: Double = a.doubleValue
    def charValue: Char = a.charValue
  }


  implicit def treeHelper(a: Tree): TreeHelper = new TreeHelper {
    def symbol: Symbol = a.symbol

    def pos: Position = a.pos

    def isEmpty: Boolean = a.isEmpty

    def tpe: Type = a.tpe

    def exists(pred: (Tree) => Boolean): Boolean = a.find(pred).isDefined
  }


  implicit def annotHelper(a: Annotation): AnnotationHelper = new AnnotationHelper {
    def atp: Type = a.tree.tpe

    def assocs: List[(Name, Object)] = ???

    def symbol: Symbol = a.tree.symbol

    def args: List[Tree] = ???
  }


  implicit def nameHelper(n: Name): NameHelper = new NameHelper {
    def toTypeName: Name = n.toTypeName
    def isTypeName: Boolean = n.isTypeName
    def toTermName: Name = n.toTermName
    def dropModule: Name = ???

    def len: Int = n.length
    def offset: Int = n.start
    def isTermName: Boolean = n.isTermName
    def startsWith(s: String): Boolean = n.startsWith(s)
  }


  implicit def symHelper(sym: Symbol): SymbolHelper = new SymbolHelper {
    // names
    def fullName(sep: Char): String = sym.showFullName
    def fullName: String = sym.showFullName
    def simpleName: Name = sym.name
    def javaSimpleName: Name = toDenot(sym).name // addModuleSuffix(simpleName.dropLocal)
    def javaBinaryName: Name = toDenot(sym).fullNameSeparated('/') // addModuleSuffix(fullNameInternal('/'))
    def javaClassName: String = toDenot(sym).fullName.toString// addModuleSuffix(fullNameInternal('.')).toString
    def name: Name = sym.name
    def rawname: Name = sym.name // todo ????

    // types
    def info: Type = toDenot(sym).info
    def tpe: Type = toDenot(sym).info // todo whats the differentce between tpe and info?
    def thisType: Type = toDenot(sym).thisType

    // tests
    def isClass: Boolean = {
      sym.isClass && (sym.isPackageObject || !(sym is Flags.Package))
    }
    def isType: Boolean = sym.isType
    def isAnonymousClass: Boolean = toDenot(sym).isAnonymousClass
    def isConstructor: Boolean = toDenot(sym).isConstructor
    def isAnonymousFunction: Boolean = toDenot(sym).isAnonymousFunction
    def isMethod: Boolean = sym is Flags.Method
    def isPublic: Boolean =  sym.flags.is(Flags.EmptyFlags, Flags.Private | Flags.Protected)
    def isSynthetic: Boolean = sym is Flags.Synthetic
    def isPackageClass: Boolean = sym is Flags.PackageClass
    def isModuleClass: Boolean = sym is Flags.ModuleClass
    def isModule: Boolean = sym is Flags.Module
    def isStrictFP: Boolean = false // todo: implement
    def isLabel: Boolean = sym is Flags.Label
    def hasPackageFlag: Boolean = sym is Flags.Package
    def isImplClass: Boolean = sym is Flags.ImplClass
    def isInterface: Boolean = (sym is Flags.PureInterface) || (sym is Flags.Trait)
    def hasGetter: Boolean = false // used only for generaration of beaninfo todo: implement
    def isGetter: Boolean = toDenot(sym).isGetter
    def isSetter: Boolean = toDenot(sym).isSetter
    def isGetClass: Boolean = sym eq defn.Any_getClass
    def isJavaDefined: Boolean = sym is Flags.JavaDefined
    def isJavaDefaultMethod: Boolean = !((sym is Flags.Deferred)  || toDenot(sym).isClassConstructor)
    def isDeferred: Boolean = sym is Flags.Deferred
    def isPrivate: Boolean = sym is Flags.Private
    def getsJavaFinalFlag: Boolean =
      isFinal &&  !toDenot(sym).isClassConstructor && !(sym is Flags.Mutable) &&  !(sym.enclosingClass is Flags.JavaInterface)

    def getsJavaPrivateFlag: Boolean =
      isPrivate //|| (sym.isPrimaryConstructor && sym.owner.isTopLevelModuleClass)

    def isFinal: Boolean = sym is Flags.Final
    def isStaticMember: Boolean = (sym ne NoSymbol) && ((sym is Flags.JavaStatic) || (owner is Flags.ImplClass))
      // guard against no sumbol cause this code is executed to select which call type(static\dynamic) to use to call array.clone

    def isBottomClass: Boolean = (sym ne defn.NullClass) && (sym ne defn.NothingClass)
    def isBridge: Boolean = sym is Flags.Bridge
    def isArtifact: Boolean = sym is Flags.Artifact
    def hasEnumFlag: Boolean = sym is Flags.Enum
    def hasAccessBoundary: Boolean = sym.accessBoundary(defn.RootClass) ne defn.RootClass
    def isVarargsMethod: Boolean = sym is Flags.JavaVarargs
    def isDeprecated: Boolean = false
    def isMutable: Boolean = sym is Flags.Mutable
    def hasAbstractFlag: Boolean = (sym is Flags.Abstract) || (sym is Flags.JavaInterface)
    def hasModuleFlag: Boolean = sym is Flags.Module
    def isSynchronized: Boolean = sym is Flags.Synchronized
    def isNonBottomSubClass(other: Symbol): Boolean = sym.derivesFrom(other)
    def hasAnnotation(sym: Symbol): Boolean = false
    def shouldEmitForwarders: Boolean =  //exitingPickler { !(sym.name.toString contains '$')
      (sym is Flags.Module) && !(sym is Flags.ImplClass) /// !sym.isNestedClass
    def isJavaEntryPoint: Boolean = CollectEntryPoints.isJavaEntyPoint(sym)

    def isClassConstructor: Boolean = toDenot(sym).isClassConstructor

    /**
     * True for module classes of modules that are top-level or owned only by objects. Module classes
     * for such objects will get a MODULE$ flag and a corresponding static initializer.
     */
    def isStaticModuleClass: Boolean = sym.isStatic && (sym is Flags.Module)

    def isStaticConstructor: Boolean = isStaticMember && isClassConstructor


    // navigation
    def owner: Symbol = toDenot(sym).owner
    def rawowner: Symbol = owner
    def originalOwner: Symbol = {
      try {
        if (sym.exists) {
          val original = toDenot(sym).initial
          val validity = original.validFor
          val shiftedContext = ctx.withPhase(validity.phaseId)
          val r = toDenot(sym)(shiftedContext).maybeOwner
          if(r is Flags.Package) NoSymbol
          else r
        } else NoSymbol
      } catch {
        case e: NotDefinedHere => NoSymbol // todo: do we have a method to tests this?
      }
    }
    def parentSymbols: List[Symbol] = toDenot(sym).info.parents.map(_.typeSymbol)
    def superClass: Symbol = toDenot(sym).superClass
    def enclClass: Symbol = toDenot(sym).enclosingClass
    def linkedClassOfClass: Symbol = linkedClass
    def linkedClass: Symbol = toDenot(sym).linkedClass //exitingPickler(sym.linkedClassOfClass)
    def companionClass: Symbol = toDenot(sym).companionClass
    def companionModule: Symbol = toDenot(sym).companionModule
    def companionSymbol: Symbol = if (sym is Flags.Module) companionClass else companionModule
    def moduleClass: Symbol = toDenot(sym).moduleClass
    def enclosingClassSym: Symbol = enclClass //todo is handled specially for JavaDefined symbols in scalac



    // members
    def primaryConstructor: Symbol = toDenot(sym).primaryConstructor
    def nestedClasses: List[Symbol] = memberClasses //exitingPhase(currentRun.lambdaliftPhase)(sym.memberClasses)
    def memberClasses: List[Symbol] = toDenot(sym).info.memberClasses.map(_.symbol).toList
    def annotations: List[Annotation] = Nil
    def companionModuleMembers: List[Symbol] =  {
      // phase travel to exitingPickler: this makes sure that memberClassesOf only sees member classes,
      // not local classes of the companion module (E in the exmaple) that were lifted by lambdalift.
      if (linkedClass.isTopLevelModuleClass) /*exitingPickler*/ linkedClass.memberClasses
      else Nil
    }
    def fieldSymbols: List[Symbol] = toDenot(sym).info.memberClasses.map(_.symbol).toList
    def methodSymbols: List[Symbol] =
      for (f <- toDenot(sym).info.decls.toList if !f.isMethod && f.isTerm && !f.isModule) yield f
    def serialVUID: Option[Long] = None


    def freshLocal(cunit: CompilationUnit, name: String, tpe: Type, pos: Position, flags: Flags): Symbol = {
      ctx.newSymbol(sym, name.toTermName, FlagSet(flags), tpe, NoSymbol, pos)
    }

    def getter(clz: Symbol): Symbol = decorateSymbol(sym).getter
    def setter(clz: Symbol): Symbol = decorateSymbol(sym).setter

    def moduleSuffix: String = "" // todo: validate that names already have $ suffix
    def outputDirectory: AbstractFile = new PlainDirectory(new Directory(new JFile(ctx.settings.d.value)))
    def pos: Position = sym.pos

    def throwsAnnotations: List[Symbol] = Nil

    /**
     * All interfaces implemented by a class, except for those inherited through the superclass.
     *
     */
    def superInterfaces: List[Symbol] = decorateSymbol(sym).superInterfaces

    /**
     * True for module classes of package level objects. The backend will generate a mirror class for
     * such objects.
     */
    def isTopLevelModuleClass: Boolean = sym.isModuleClass && sym.isStatic

    /**
     * This is basically a re-implementation of sym.isStaticOwner, but using the originalOwner chain.
     *
     * The problem is that we are interested in a source-level property. Various phases changed the
     * symbol's properties in the meantime, mostly lambdalift modified (destructively) the owner.
     * Therefore, `sym.isStatic` is not what we want. For example, in
     *   object T { def f { object U } }
     * the owner of U is T, so UModuleClass.isStatic is true. Phase travel does not help here.
     */
    def isOriginallyStaticOwner: Boolean = sym.isStatic


    def addRemoteRemoteExceptionAnnotation: Unit = ()
  }


  implicit def typeHelper(tp: Type): TypeHelper = new TypeHelper {
    def member(string: Name): Symbol = tp.member(string.toTermName).symbol

    def isFinalType: Boolean = tp.typeSymbol is Flags.Final //in scalac checks for type parameters. Why? Aren't they gone by backend?

    def underlying: Type = tp match {
      case t: TypeProxy => t.underlying
      case _ => tp
    }

    def paramTypes: List[Type] = tp.firstParamTypes

    def <:<(other: Type): Boolean = tp <:< other

    def memberInfo(s: Symbol): Type = tp.memberInfo(s)

    def decls: List[Symbol] = tp.decls.map(_.symbol).toList

    def members: List[Symbol] =
      tp.memberDenots(takeAllFilter, (name, buf) => buf ++= member(name).alternatives).map(_.symbol).toList

    def typeSymbol: Symbol = tp.widenDealias.typeSymbol

    def =:=(other: Type): Boolean = tp =:= other

    def membersBasedOnFlags(excludedFlags: Flags, requiredFlags: Flags): List[Symbol] =
      tp.membersBasedOnFlags(FlagSet(requiredFlags), FlagSet(excludedFlags)).map(_.symbol).toList

    def resultType: Type = tp.resultType

    def toTypeKind(ct: BCodeHelpers)(storage: ct.BCInnerClassGen): ct.bTypes.BType = {
      import ct.bTypes._
      val defn = ctx.definitions
      import coreBTypes._
      import Types._
      /**
       * Primitive types are represented as TypeRefs to the class symbol of, for example, scala.Int.
       * The `primitiveTypeMap` maps those class symbols to the corresponding PrimitiveBType.
       */
      def primitiveOrClassToBType(sym: Symbol): BType = {
        assert(sym.isClass, sym)
        assert(sym != ArrayClass || isCompilingArray, sym)
        primitiveTypeMap.getOrElse(sym, storage.getClassBTypeAndRegisterInnerClass(sym.asInstanceOf[ct.int.Symbol]))
      }

      /**
       * When compiling Array.scala, the type parameter T is not erased and shows up in method
       * signatures, e.g. `def apply(i: Int): T`. A TyperRef to T is replaced by ObjectReference.
       */
      def nonClassTypeRefToBType(sym: Symbol): ClassBType = {
        assert(sym.isType && isCompilingArray, sym)
        ObjectReference
      }

      tp.widenDealias match {
        case JavaArrayType(el) =>ArrayBType(el.toTypeKind(ct)(storage)) // Array type such as Array[Int] (kept by erasure)
        case t: TypeRef =>
          t.info match {

            case _ =>
              if(!t.symbol.isClass) nonClassTypeRefToBType(t.symbol)  // See comment on nonClassTypeRefToBType
              else primitiveOrClassToBType(t.symbol) // Common reference to a type such as scala.Int or java.lang.String
          }
        case Types.ClassInfo(_, sym, _, _, _)           => primitiveOrClassToBType(sym) // We get here, for example, for genLoadModule, which invokes toTypeKind(moduleClassSymbol.info)

        case t: MethodType => // triggers for LabelDefs
          t.resultType.toTypeKind(ct)(storage)

        /* AnnotatedType should (probably) be eliminated by erasure. However we know it happens for
         * meta-annotated annotations (@(ann @getter) val x = 0), so we don't emit a warning.
         * The type in the AnnotationInfo is an AnnotatedTpe. Tested in jvm/annotations.scala.
         */
        case a @ AnnotatedType(_, t) =>
          debuglog(s"typeKind of annotated type $a")
          t.toTypeKind(ct)(storage)

        /* ExistentialType should (probably) be eliminated by erasure. We know they get here for
         * classOf constants:
         *   class C[T]
         *   class T { final val k = classOf[C[_]] }
         */
       /* case e @ ExistentialType(_, t) =>
          debuglog(s"typeKind of existential type $e")
          t.toTypeKind(ctx)(storage)*/

        /* The cases below should probably never occur. They are kept for now to avoid introducing
         * new compiler crashes, but we added a warning. The compiler / library bootstrap and the
         * test suite don't produce any warning.
         */

        case tp =>
          ctx.warning(
            s"an unexpected type representation reached the compiler backend while compiling $currentUnit: $tp. " +
              "If possible, please file a bug on issues.scala-lang.org.")

          tp match {
            case ThisType(ArrayClass)               => ObjectReference // was introduced in 9b17332f11 to fix SI-999, but this code is not reached in its test, or any other test
            case ThisType(sym)                      => storage.getClassBTypeAndRegisterInnerClass(sym.asInstanceOf[ct.int.Symbol])
           // case t: SingletonType                 => primitiveOrClassToBType(t.classSymbol)
            case t: SingletonType                  => t.underlying.toTypeKind(ct)(storage)
            case t: RefinedType                   =>  t.parent.toTypeKind(ct)(storage) //parents.map(_.toTypeKind(ct)(storage).asClassBType).reduceLeft((a, b) => a.jvmWiseLUB(b))
          }
      }
    }

    def summaryString: String = tp.showSummary

    def params: List[Symbol] = Nil // used only for emmiting annotations

    def parents: List[Type] = tp.parents
  }



  object Assign extends AssignDeconstructor {
    def _1: Tree = field.lhs
    def _2: Tree = field.rhs
  }

  object Select extends SelectDeconstructor {
    def _1: Tree = field.qualifier
    def _2: Name = field.name
  }

  object Apply extends ApplyDeconstructor {
    def _1: Tree = field.fun
    def _2: List[Tree] = field.args
  }

  object If extends IfDeconstructor {
    def _1: Tree = field.cond
    def _2: Tree = field.thenp
    def _3: Tree = field.elsep
  }

  object ValDef extends ValDefDeconstructor {
    def _1: Modifiers = field.mods
    def _2: Name = field.name
    def _3: Tree = field.tpt
    def _4: Tree = field.rhs
  }

  object ApplyDynamic extends ApplyDynamicDeconstructor {
    def _1: Tree = ???
    def _2: List[Tree] = ???
  }

  // todo: this product1s should also eventually become name-based pattn matching
  object Literal extends LiteralDeconstructor {
    def get = field.const
  }

  object Throw extends ThrowDeconstructor {
    def get = field.args.head

    override def unapply(s: Throw): DottyBackendInterface.this.Throw.type = {
      if (s.fun.symbol eq defn.throwMethod) {
        field = s
      } else {
        field = null
      }
      this
    }
  }

  object New extends NewDeconstructor {
    def get = field.tpt.tpe
  }

  object This extends ThisDeconstructor {
    def get = field.qual
    def apply(s: Symbol): This = tpd.This(s.asClass)
  }

  object Return extends ReturnDeconstructor {
    def get = field.expr
  }

  object Ident extends IdentDeconstructor {
    def get = field.name
  }

  object Alternative extends AlternativeDeconstructor {
    def get = field.trees
  }

  object Constant extends ConstantDeconstructor {
    def get = field.value
  }
  object ThrownException extends ThrownException {
    def unapply(a: Annotation): Option[Symbol] = None // todo
  }

  object Try extends TryDeconstructor {
    def _1: Tree = field.expr
    def _2: List[Tree] = field.cases
    def _3: Tree = field.finalizer
  }

  object LabelDef extends LabelDeconstructor {
    def _1: Name = field.name
    def _2: List[Symbol] = field.vparamss.flatMap(_.map(_.symbol))
    def _3: Tree = field.rhs

    override def unapply(s: LabelDef): DottyBackendInterface.this.LabelDef.type = {
      if(s.symbol is Flags.Label) this.field = s
      else this.field = null
      this
    }
  }

  object Typed extends TypedDeconstrutor {
    def _1: Tree = field.expr
    def _2: Tree = field.tpt
  }
  object Super extends SuperDeconstructor {
    def _1: Tree = field.qual
    def _2: Name = field.mix
  }
  object ArrayValue extends ArrayValueDeconstructor {
    def _1: Type = field.tpe match {
      case JavaArrayType(elem) => elem
      case _ =>
        ctx.error(s"JavaSeqArray with type ${field.tpe} reached backend: $field", field.pos)
        ErrorType
    }
    def _2: List[Tree] = field.elems
  }
  object Match extends MatchDeconstructor {
    def _1: Tree = field.selector
    def _2: List[Tree] = field.cases
  }
  object Block extends BlockDeconstructor {
    def _1: List[Tree] = field.stats
    def _2: Tree = field.expr
  }
  object TypeApply extends TypeApplyDeconstructor {
    def _1: Tree = field.fun
    def _2: List[Tree] = field.args
  }
  object CaseDef extends CaseDeconstructor {
    def _1: Tree = field.pat
    def _2: Tree = field.guard
    def _3: Tree = field.body
  }

  object DefDef extends DefDefDeconstructor {
    def _1: Modifiers = field.mods
    def _2: Name = field.name
    def _3: List[TypeDef] = field.tparams
    def _4: List[List[ValDef]] = field.vparamss
    def _5: Tree = field.tpt
    def _6: Tree = field.rhs
  }

  object ModuleDef extends ModuleDefDeconstructor {
    def _1: Modifiers = ???
    def _2: Name = ???
    def _3: Tree = ???
  }

  object Template extends TemplateDeconstructor {
    def _1: List[Tree] = field.parents
    def _2: ValDef = field.self
    def _3: List[Tree] = field.constr :: field.body
  }

  object Bind extends BindDeconstructor {
    def _1: Name = field.name
    def _2: Tree = field.body
  }

  object ClassDef extends ClassDefDeconstructor {
    def _1: Modifiers = field.mods
    def _2: Name = field.name
    def _4: Template = field.rhs.asInstanceOf[Template]
    def _3: List[TypeDef] = Nil
  }

  object Closure extends ClosureDeconstructor {
    def _1 = field.env
    def _2 = field.meth
    def _3 = {
      val t = field.tpt.tpe.typeSymbol
      if(t.exists) t
      else {
        val arity = field.meth.tpe.widenDealias.paramTypes.size - _1.size
        val returnsUnit = field.meth.tpe.widenDealias.resultType.classSymbol == UnitClass
        if(returnsUnit)
          ctx.requiredClass(("scala.compat.java8.JProcedure"+arity).toTermName)
        else ctx.requiredClass(("scala.compat.java8.JFunction"+arity).toTermName)
      }
    }
  }

  def currentUnit = ctx.compilationUnit
}