package scala.tools.nsc
package backend.jvm

import scala.annotation.switch
import scala.tools.asm
import scala.tools.nsc.backend.jvm.BTypes.InternalName

/**
 * Core BTypes and some other definitions. The initialization of these definitions requires access
 * to symbols / types (global).
 *
 * The symbols used to initialize the ClassBTypes may change from one compiler run to the next. To
 * make sure the definitions are consistent with the symbols in the current run, the
 * `intializeCoreBTypes` method in BTypesFromSymbols creates a new instance of CoreBTypes in each
 * compiler run.
 *
 * The class BTypesFromSymbols does not directly reference CoreBTypes, but CoreBTypesProxy. The
 * reason is that having a `var bTypes: CoreBTypes` would not allow `import bTypes._`. Instead, the
 * proxy class holds a `CoreBTypes` in a variable field and forwards to this instance.
 *
 * The definitions in `CoreBTypes` need to be lazy vals to break an initialization cycle. When
 * creating a new instance to assign to the proxy, the `classBTypeFromSymbol` invoked in the
 * constructor will actually go through the proxy. The lazy vals make sure the instance is assigned
 * in the proxy before the fields are initialized.
 *
 * Note: if we did not re-create the core BTypes on each compiler run, BType.classBTypeFromInternalNameMap
 * could not be a perRunCache anymore: the classes defined here need to be in that map, they are
 * added when the ClassBTypes are created. The per run cache removes them, so they would be missing
 * in the second run.
 */
class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
  import bTypes._
  import global._
  import rootMirror.{requiredClass, requiredModule, getRequiredClass, getClassIfDefined}
  import definitions._

  /**
   * Maps primitive types to their corresponding PrimitiveBType. The map is defined lexically above
   * the first use of `classBTypeFromSymbol` because that method looks at the map.
   */
  lazy val primitiveTypeToBType: Map[Symbol, PrimitiveBType] = Map(
    UnitClass    -> UNIT,
    BooleanClass -> BOOL,
    CharClass    -> CHAR,
    ByteClass    -> BYTE,
    ShortClass   -> SHORT,
    IntClass     -> INT,
    LongClass    -> LONG,
    FloatClass   -> FLOAT,
    DoubleClass  -> DOUBLE)

  /**
   * Map from primitive types to their boxed class type. Useful when pushing class literals onto the
   * operand stack (ldc instruction taking a class literal), see genConstant.
   */
  lazy val boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType] = Map(
    UNIT   -> classBTypeFromSymbol(requiredClass[java.lang.Void]),
    BOOL   -> classBTypeFromSymbol(BoxedBooleanClass),
    BYTE   -> classBTypeFromSymbol(BoxedByteClass),
    SHORT  -> classBTypeFromSymbol(BoxedShortClass),
    CHAR   -> classBTypeFromSymbol(BoxedCharacterClass),
    INT    -> classBTypeFromSymbol(BoxedIntClass),
    LONG   -> classBTypeFromSymbol(BoxedLongClass),
    FLOAT  -> classBTypeFromSymbol(BoxedFloatClass),
    DOUBLE -> classBTypeFromSymbol(BoxedDoubleClass))

  lazy val boxedClasses: Set[ClassBType] = boxedClassOfPrimitive.values.toSet

  /**
   * Maps the method symbol for a box method to the boxed type of the result. For example, the
   * method symbol for `Byte.box()` is mapped to the ClassBType `java/lang/Byte`.
   */
  lazy val boxResultType: Map[Symbol, ClassBType] = {
    for ((valueClassSym, boxMethodSym) <- currentRun.runDefinitions.boxMethod)
    yield boxMethodSym -> boxedClassOfPrimitive(primitiveTypeToBType(valueClassSym))
  }

  /**
   * Maps the method symbol for an unbox method to the primitive type of the result.
   * For example, the method symbol for `Byte.unbox()`) is mapped to the PrimitiveBType BYTE. */
  lazy val unboxResultType: Map[Symbol, PrimitiveBType] = {
    for ((valueClassSym, unboxMethodSym) <- currentRun.runDefinitions.unboxMethod)
    yield unboxMethodSym -> primitiveTypeToBType(valueClassSym)
  }

  /*
   * RT_NOTHING and RT_NULL exist at run-time only. They are the bytecode-level manifestation (in
   * method signatures only) of what shows up as NothingClass (scala.Nothing) resp. NullClass
   * (scala.Null) in Scala ASTs.
   *
   * Therefore, when RT_NOTHING or RT_NULL are to be emitted, a mapping is needed: the internal
   * names of NothingClass and NullClass can't be emitted as-is.
   */
  lazy val srNothingRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.Nothing$])
  lazy val srNullRef    : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.Null$])

  lazy val ObjectRef                 : ClassBType = classBTypeFromSymbol(ObjectClass)
  lazy val StringRef                 : ClassBType = classBTypeFromSymbol(StringClass)
  lazy val PredefRef                 : ClassBType = classBTypeFromSymbol(PredefModule.moduleClass)
  lazy val jlStringBuilderRef        : ClassBType = classBTypeFromSymbol(JavaStringBuilderClass)
  lazy val jlStringBufferRef         : ClassBType = classBTypeFromSymbol(JavaStringBufferClass)
  lazy val jlCharSequenceRef         : ClassBType = classBTypeFromSymbol(JavaCharSequenceClass)
  lazy val jlThrowableRef            : ClassBType = classBTypeFromSymbol(ThrowableClass)
  lazy val jlCloneableRef            : ClassBType = classBTypeFromSymbol(JavaCloneableClass)        // java/lang/Cloneable
  lazy val jiSerializableRef         : ClassBType = classBTypeFromSymbol(JavaSerializableClass)     // java/io/Serializable
  lazy val jlClassCastExceptionRef   : ClassBType = classBTypeFromSymbol(ClassCastExceptionClass)   // java/lang/ClassCastException
  lazy val juMapRef                  : ClassBType = classBTypeFromSymbol(JavaUtilMap)               // java/util/Map
  lazy val juHashMapRef              : ClassBType = classBTypeFromSymbol(JavaUtilHashMap)           // java/util/HashMap
  lazy val sbScalaBeanInfoRef        : ClassBType = classBTypeFromSymbol(requiredClass[scala.beans.ScalaBeanInfo])
  lazy val jliSerializedLambdaRef    : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.SerializedLambda])
  lazy val jliMethodHandlesRef       : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodHandles])
  lazy val jliMethodHandlesLookupRef : ClassBType = classBTypeFromSymbol(exitingPickler(getRequiredClass("java.lang.invoke.MethodHandles.Lookup"))) // didn't find a reliable non-stringly-typed way that works for inner classes in the backend
  lazy val jliMethodTypeRef          : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodType])
  lazy val jliCallSiteRef            : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.CallSite])
  lazy val jliLambdaMetafactoryRef   : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.LambdaMetafactory])
  lazy val srBoxesRunTimeRef         : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BoxesRunTime])
  lazy val srSymbolLiteral           : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.SymbolLiteral])
  lazy val srStructuralCallSite      : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.StructuralCallSite])
  lazy val srLambdaDeserialize       : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.LambdaDeserialize])
  lazy val srBoxedUnitRef            : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BoxedUnit])

  private def methodNameAndType(cls: Symbol, name: Name, static: Boolean = false, filterOverload: Symbol => Boolean = _ => true): MethodNameAndType = {
    val holder = if (static) cls.companionModule.moduleClass else cls
    val method = holder.info.member(name).suchThat(filterOverload)
    assert(!method.isOverloaded, method)
    MethodNameAndType(name.toString, methodBTypeFromSymbol(method))
  }

  private def srBoxesRuntimeMethods(getName: (String, String) => String): Map[BType, MethodNameAndType] = {
    ScalaValueClassesNoUnit.map(primitive => {
      val bType = primitiveTypeToBType(primitive)
      val name = newTermName(getName(primitive.name.toString, boxedClass(primitive).name.toString))
      (bType, methodNameAndType(BoxesRunTimeClass, name))
    })(collection.breakOut)
  }

  // Z -> MethodNameAndType(boxToBoolean,(Z)Ljava/lang/Boolean;)
  lazy val srBoxesRuntimeBoxToMethods: Map[BType, MethodNameAndType] = srBoxesRuntimeMethods((primitive, boxed) => "boxTo" + boxed)

  // Z -> MethodNameAndType(unboxToBoolean,(Ljava/lang/Object;)Z)
  lazy val srBoxesRuntimeUnboxToMethods: Map[BType, MethodNameAndType] = srBoxesRuntimeMethods((primitive, boxed) => "unboxTo" + primitive)

  def singleParamOfClass(cls: Symbol) = (s: Symbol) => s.paramss match {
    case List(List(param)) => param.info.typeSymbol == cls
    case _ => false
  }

  // java/lang/Boolean -> MethodNameAndType(valueOf,(Z)Ljava/lang/Boolean;)
  lazy val javaBoxMethods: Map[InternalName, MethodNameAndType] = {
    ScalaValueClassesNoUnit.map(primitive => {
      val boxed = boxedClass(primitive)
      val method = methodNameAndType(boxed, newTermName("valueOf"), static = true, filterOverload = singleParamOfClass(primitive))
      (classBTypeFromSymbol(boxed).internalName, method)
    })(collection.breakOut)
  }

  // java/lang/Boolean -> MethodNameAndType(booleanValue,()Z)
  lazy val javaUnboxMethods: Map[InternalName, MethodNameAndType] = {
    ScalaValueClassesNoUnit.map(primitive => {
      val boxed = boxedClass(primitive)
      val name = primitive.name.toString.toLowerCase + "Value"
      (classBTypeFromSymbol(boxed).internalName, methodNameAndType(boxed, newTermName(name)))
    })(collection.breakOut)
  }

  private def predefBoxingMethods(getName: (String, String) => String): Map[String, MethodBType] = {
    ScalaValueClassesNoUnit.map(primitive => {
      val boxed = boxedClass(primitive)
      val name = getName(primitive.name.toString, boxed.name.toString)
      (name, methodNameAndType(PredefModule.moduleClass, newTermName(name)).methodType)
    })(collection.breakOut)
  }

  // boolean2Boolean -> (Z)Ljava/lang/Boolean;
  lazy val predefAutoBoxMethods: Map[String, MethodBType] = predefBoxingMethods((primitive, boxed) => primitive.toLowerCase + "2" + boxed)

  // Boolean2boolean -> (Ljava/lang/Boolean;)Z
  lazy val predefAutoUnboxMethods: Map[String, MethodBType] = predefBoxingMethods((primitive, boxed) => boxed + "2" + primitive.toLowerCase)

  private def staticRefMethods(name: Name): Map[InternalName, MethodNameAndType] = {
    allRefClasses.map(refClass =>
      (classBTypeFromSymbol(refClass).internalName, methodNameAndType(refClass, name, static = true)))(collection.breakOut)
  }

  // scala/runtime/BooleanRef -> MethodNameAndType(create,(Z)Lscala/runtime/BooleanRef;)
  lazy val srRefCreateMethods: Map[InternalName, MethodNameAndType] = staticRefMethods(nme.create)

  // scala/runtime/BooleanRef -> MethodNameAndType(zero,()Lscala/runtime/BooleanRef;)
  lazy val srRefZeroMethods: Map[InternalName, MethodNameAndType] = staticRefMethods(nme.zero)

  // java/lang/Boolean -> MethodNameAndType(<init>,(Z)V)
  lazy val primitiveBoxConstructors: Map[InternalName, MethodNameAndType] = {
    ScalaValueClassesNoUnit.map(primitive => {
      val boxed = boxedClass(primitive)
      (classBTypeFromSymbol(boxed).internalName, methodNameAndType(boxed, nme.CONSTRUCTOR, filterOverload = singleParamOfClass(primitive)))
    })(collection.breakOut)
  }

  private def nonOverloadedConstructors(classes: Iterable[Symbol]): Map[InternalName, MethodNameAndType] = {
    classes.map(cls => (classBTypeFromSymbol(cls).internalName, methodNameAndType(cls, nme.CONSTRUCTOR)))(collection.breakOut)
  }

  // scala/runtime/BooleanRef -> MethodNameAndType(<init>,(Z)V)
  lazy val srRefConstructors: Map[InternalName, MethodNameAndType] = nonOverloadedConstructors(allRefClasses)

  private def specializedSubclasses(cls: Symbol): List[Symbol] = {
    exitingSpecialize(cls.info) // the `transformInfo` method of specialization adds specialized subclasses to the `specializedClass` map
    specializeTypes.specializedClass.collect({
      case ((`cls`, _), specCls) => specCls
    }).toList
  }

  // scala/Tuple3 -> MethodNameAndType(<init>,(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V)
  // scala/Tuple2$mcZC$sp -> MethodNameAndType(<init>,(ZC)V)
  lazy val tupleClassConstructors: Map[InternalName, MethodNameAndType] = {
    val tupleClassSymbols = TupleClass.seq ++ specializedSubclasses(TupleClass(1)) ++ specializedSubclasses(TupleClass(2))
    nonOverloadedConstructors(tupleClassSymbols)
  }

  // enumeration of specialized classes is temporary, while we still use the java-defined JFunctionN.
  // once we switch to ordinary FunctionN, we can use specializedSubclasses just like for tuples.
  private def functionClasses(base: String): Set[Symbol] = {
    def primitives = Iterator("B", "S", "I", "J", "C", "F", "D", "Z", "V")
    def ijfd = Iterator("I", "J", "F", "D")
    def ijfdzv = Iterator("I", "J", "F", "D", "Z", "V")
    def ijd = Iterator("I", "J", "D")
    val classNames = Set.empty[String] ++ {
      (0 to 22).map(base + _)
    } ++ {
      primitives.map(base + "0$mc" + _ + "$sp") // Function0
    } ++ {
      // return type specializations appear first in the name string (alphabetical sorting)
      for (r <- ijfdzv; a <- ijfd) yield base + "1$mc" + r + a + "$sp" // Function1
    } ++ {
      for (r <- ijfdzv; a <- ijd; b <- ijd) yield base + "2$mc" + r + a + b + "$sp" // Function2
    }
    classNames map getRequiredClass
  }

  lazy val srJFunctionRefs: Set[InternalName] = functionClasses("scala.runtime.java8.JFunction").map(classBTypeFromSymbol(_).internalName)

  lazy val typeOfArrayOp: Map[Int, BType] = {
    import scalaPrimitives._
    Map(
      (List(ZARRAY_LENGTH, ZARRAY_GET, ZARRAY_SET) map (_ -> BOOL))   ++
        (List(BARRAY_LENGTH, BARRAY_GET, BARRAY_SET) map (_ -> BYTE))   ++
        (List(SARRAY_LENGTH, SARRAY_GET, SARRAY_SET) map (_ -> SHORT))  ++
        (List(CARRAY_LENGTH, CARRAY_GET, CARRAY_SET) map (_ -> CHAR))   ++
        (List(IARRAY_LENGTH, IARRAY_GET, IARRAY_SET) map (_ -> INT))    ++
        (List(LARRAY_LENGTH, LARRAY_GET, LARRAY_SET) map (_ -> LONG))   ++
        (List(FARRAY_LENGTH, FARRAY_GET, FARRAY_SET) map (_ -> FLOAT))  ++
        (List(DARRAY_LENGTH, DARRAY_GET, DARRAY_SET) map (_ -> DOUBLE)) ++
        (List(OARRAY_LENGTH, OARRAY_GET, OARRAY_SET) map (_ -> ObjectRef)) : _*
    )
  }

  lazy val hashMethodSym: Symbol = getMember(ScalaRunTimeModule, nme.hash_)

  // TODO @lry avoiding going through through missingHook for every line in the REPL: https://github.com/scala/scala/commit/8d962ed4ddd310cc784121c426a2e3f56a112540
  lazy val AndroidParcelableInterface : Symbol = getClassIfDefined("android.os.Parcelable")
  lazy val AndroidCreatorClass        : Symbol = getClassIfDefined("android.os.Parcelable$Creator")

  lazy val BeanInfoAttr: Symbol = requiredClass[scala.beans.BeanInfo]

  /* The Object => String overload. */
  lazy val String_valueOf: Symbol = {
    getMember(StringModule, nme.valueOf) filter (sym => sym.info.paramTypes match {
      case List(pt) => pt.typeSymbol == ObjectClass
      case _        => false
    })
  }

  lazy val lambdaMetaFactoryBootstrapHandle =
    new asm.Handle(asm.Opcodes.H_INVOKESTATIC,
      coreBTypes.jliLambdaMetafactoryRef.internalName, sn.AltMetafactory.toString,
      MethodBType(
        List(
          coreBTypes.jliMethodHandlesLookupRef,
          coreBTypes.StringRef,
          coreBTypes.jliMethodTypeRef,
          ArrayBType(ObjectRef)),
        coreBTypes.jliCallSiteRef
      ).descriptor)

  lazy val lambdaDeserializeBootstrapHandle =
    new scala.tools.asm.Handle(scala.tools.asm.Opcodes.H_INVOKESTATIC,
      coreBTypes.srLambdaDeserialize.internalName, sn.Bootstrap.toString,
      MethodBType(
        List(
          coreBTypes.jliMethodHandlesLookupRef,
          coreBTypes.StringRef,
          coreBTypes.jliMethodTypeRef
        ),
        coreBTypes.jliCallSiteRef
      ).descriptor)
}

/**
 * This trait make some core BTypes available that don't depend on a Global instance. Some core
 * BTypes are required to be accessible in the BTypes trait, which does not have access to Global.
 *
 * BTypes cannot refer to CoreBTypesProxy because some of its members depend on global, for example
 * the type Symbol in
 *   def primitiveTypeMap: Map[Symbol, PrimitiveBType]
 */
trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] {
  val bTypes: BTS
  import bTypes._

  def boxedClasses: Set[ClassBType]
  def boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType]

  def srNothingRef              : ClassBType
  def srNullRef                 : ClassBType

  def ObjectRef                 : ClassBType
  def StringRef                 : ClassBType
  def PredefRef                 : ClassBType
  def jlCloneableRef            : ClassBType
  def jiSerializableRef         : ClassBType
  def juHashMapRef              : ClassBType
  def juMapRef                  : ClassBType
  def jliCallSiteRef            : ClassBType
  def jliMethodTypeRef          : ClassBType
  def jliSerializedLambdaRef    : ClassBType
  def jliMethodHandlesLookupRef : ClassBType
  def srBoxesRunTimeRef         : ClassBType
  def srBoxedUnitRef            : ClassBType

  def srBoxesRuntimeBoxToMethods   : Map[BType, MethodNameAndType]
  def srBoxesRuntimeUnboxToMethods : Map[BType, MethodNameAndType]

  def javaBoxMethods   : Map[InternalName, MethodNameAndType]
  def javaUnboxMethods : Map[InternalName, MethodNameAndType]

  def predefAutoBoxMethods   : Map[String, MethodBType]
  def predefAutoUnboxMethods : Map[String, MethodBType]

  def srRefCreateMethods : Map[InternalName, MethodNameAndType]
  def srRefZeroMethods   : Map[InternalName, MethodNameAndType]

  def primitiveBoxConstructors : Map[InternalName, MethodNameAndType]
  def srRefConstructors        : Map[InternalName, MethodNameAndType]
  def tupleClassConstructors   : Map[InternalName, MethodNameAndType]

  def srJFunctionRefs: Set[InternalName]

  def lambdaMetaFactoryBootstrapHandle  : asm.Handle
  def lambdaDeserializeBootstrapHandle  : asm.Handle
}

/**
 * See comment in class [[CoreBTypes]].
 */
final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) extends CoreBTypesProxyGlobalIndependent[BTFS] {
  import bTypes._
  import global._

  private[this] var _coreBTypes: CoreBTypes[bTypes.type] = _
  def setBTypes(coreBTypes: CoreBTypes[BTFS]): Unit = {
    _coreBTypes = coreBTypes.asInstanceOf[CoreBTypes[bTypes.type]]
  }

  def primitiveTypeToBType: Map[Symbol, PrimitiveBType] = _coreBTypes.primitiveTypeToBType

  def boxedClasses: Set[ClassBType] = _coreBTypes.boxedClasses
  def boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType] = _coreBTypes.boxedClassOfPrimitive

  def boxResultType: Map[Symbol, ClassBType] = _coreBTypes.boxResultType
  def unboxResultType: Map[Symbol, PrimitiveBType] = _coreBTypes.unboxResultType

  def srNothingRef              : ClassBType = _coreBTypes.srNothingRef
  def srNullRef                 : ClassBType = _coreBTypes.srNullRef

  def ObjectRef                 : ClassBType = _coreBTypes.ObjectRef
  def StringRef                 : ClassBType = _coreBTypes.StringRef
  def PredefRef                 : ClassBType = _coreBTypes.PredefRef
  def jlStringBuilderRef        : ClassBType = _coreBTypes.jlStringBuilderRef
  def jlStringBufferRef         : ClassBType = _coreBTypes.jlStringBufferRef
  def jlCharSequenceRef         : ClassBType = _coreBTypes.jlCharSequenceRef
  def jlThrowableRef            : ClassBType = _coreBTypes.jlThrowableRef
  def jlCloneableRef            : ClassBType = _coreBTypes.jlCloneableRef
  def jiSerializableRef         : ClassBType = _coreBTypes.jiSerializableRef
  def jlClassCastExceptionRef   : ClassBType = _coreBTypes.jlClassCastExceptionRef
  def juMapRef                  : ClassBType = _coreBTypes.juMapRef
  def juHashMapRef              : ClassBType = _coreBTypes.juHashMapRef
  def sbScalaBeanInfoRef        : ClassBType = _coreBTypes.sbScalaBeanInfoRef
  def jliSerializedLambdaRef    : ClassBType = _coreBTypes.jliSerializedLambdaRef
  def jliMethodHandlesRef       : ClassBType = _coreBTypes.jliMethodHandlesRef
  def jliMethodHandlesLookupRef : ClassBType = _coreBTypes.jliMethodHandlesLookupRef
  def jliMethodTypeRef          : ClassBType = _coreBTypes.jliMethodTypeRef
  def jliCallSiteRef            : ClassBType = _coreBTypes.jliCallSiteRef
  def jliLambdaMetafactoryRef   : ClassBType = _coreBTypes.jliLambdaMetafactoryRef
  def srBoxesRunTimeRef         : ClassBType = _coreBTypes.srBoxesRunTimeRef
  def srBoxedUnitRef            : ClassBType = _coreBTypes.srBoxedUnitRef

  def srBoxesRuntimeBoxToMethods   : Map[BType, MethodNameAndType] = _coreBTypes.srBoxesRuntimeBoxToMethods
  def srBoxesRuntimeUnboxToMethods : Map[BType, MethodNameAndType] = _coreBTypes.srBoxesRuntimeUnboxToMethods

  def javaBoxMethods   : Map[InternalName, MethodNameAndType] = _coreBTypes.javaBoxMethods
  def javaUnboxMethods : Map[InternalName, MethodNameAndType] = _coreBTypes.javaUnboxMethods

  def predefAutoBoxMethods   : Map[String, MethodBType] = _coreBTypes.predefAutoBoxMethods
  def predefAutoUnboxMethods : Map[String, MethodBType] = _coreBTypes.predefAutoUnboxMethods

  def srRefCreateMethods : Map[InternalName, MethodNameAndType] = _coreBTypes.srRefCreateMethods
  def srRefZeroMethods   : Map[InternalName, MethodNameAndType] = _coreBTypes.srRefZeroMethods

  def primitiveBoxConstructors : Map[InternalName, MethodNameAndType] = _coreBTypes.primitiveBoxConstructors
  def srRefConstructors        : Map[InternalName, MethodNameAndType] = _coreBTypes.srRefConstructors
  def tupleClassConstructors   : Map[InternalName, MethodNameAndType] = _coreBTypes.tupleClassConstructors

  def srJFunctionRefs: Set[InternalName] = _coreBTypes.srJFunctionRefs

  def srSymbolLiteral           : ClassBType = _coreBTypes.srSymbolLiteral
  def srStructuralCallSite      : ClassBType = _coreBTypes.srStructuralCallSite
  def srLambdaDeserialize       : ClassBType = _coreBTypes.srLambdaDeserialize

  def typeOfArrayOp: Map[Int, BType] = _coreBTypes.typeOfArrayOp

  // Some symbols. These references should probably be moved to Definitions.

  def hashMethodSym: Symbol = _coreBTypes.hashMethodSym

  def AndroidParcelableInterface : Symbol = _coreBTypes.AndroidParcelableInterface
  def AndroidCreatorClass        : Symbol = _coreBTypes.AndroidCreatorClass

  def BeanInfoAttr: Symbol = _coreBTypes.BeanInfoAttr

  def String_valueOf: Symbol = _coreBTypes.String_valueOf

  def lambdaMetaFactoryBootstrapHandle = _coreBTypes.lambdaMetaFactoryBootstrapHandle
  def lambdaDeserializeBootstrapHandle = _coreBTypes.lambdaDeserializeBootstrapHandle
}
