<commit_before>package dotty.tools
package dotc
package core

import Types._, Contexts._, Symbols._, Denotations._, SymDenotations._, StdNames._, Names._
import Flags._, Scopes._, Decorators._, NameOps._, util.Positions._
import pickling.UnPickler.ensureConstructor
import scala.annotation.{ switch, meta }
import scala.collection.{ mutable, immutable }
import PartialFunction._
import collection.mutable
import scala.reflect.api.{ Universe => ApiUniverse }

object Definitions {
  val MaxFunctionArity, MaxTupleArity = 22
}

/** A class defining symbols and types of standard definitions */
class Definitions {
  import Definitions._

  private implicit var ctx: Context = _

  private def newSymbol[N <: Name](owner: Symbol, name: N, flags: FlagSet, info: Type) =
    ctx.newSymbol(owner, name, flags | Permanent, info)

  private def newClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, infoFn: ClassSymbol => Type) =
    ctx.newClassSymbol(owner, name, flags | Permanent, infoFn).entered

  private def newCompleteClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, parents: List[TypeRef], decls: Scope = newScope) =
    ctx.newCompleteClassSymbol(owner, name, flags | Permanent, parents, decls).entered

  private def newTopClassSymbol(name: TypeName, flags: FlagSet, parents: List[TypeRef]) =
    completeClass(newCompleteClassSymbol(ScalaPackageClass, name, flags, parents))

  private def newTypeField(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
    scope.enter(newSymbol(cls, name, flags, TypeBounds.empty))

  private def newTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
    newTypeField(cls, name, flags | ClassTypeParamCreationFlags, scope)

  private def newSyntheticTypeParam(cls: ClassSymbol, scope: MutableScope, paramFlags: FlagSet, suffix: String = "T0") =
    newTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope)

  private def specialPolyClass(name: TypeName, paramFlags: FlagSet, parentConstrs: Type*): ClassSymbol = {
    val completer = new LazyType {
      def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
        val cls = denot.asClass.classSymbol
        val paramDecls = newScope
        val typeParam = newSyntheticTypeParam(cls, paramDecls, paramFlags)
        def instantiate(tpe: Type) =
          if (tpe.typeParams.nonEmpty) tpe.appliedTo(typeParam.typeRef)
          else tpe
        val parents = parentConstrs.toList map instantiate
        val parentRefs: List[TypeRef] = ctx.normalizeToClassRefs(parents, cls, paramDecls)
        denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parentRefs, paramDecls)
      }
    }
    newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer)
  }

  private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol =
    newSymbol(cls, name.encode, flags | Method, info).entered.asTerm

  private def newAliasType(name: TypeName, tpe: Type, flags: FlagSet = EmptyFlags): TypeSymbol = {
    val sym = newSymbol(ScalaPackageClass, name, flags, TypeAlias(tpe))
    ScalaPackageClass.preDecls.enter(sym)
    sym
  }

  private def newPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int,
                    resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = {
    val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount)
    val tparamBounds = tparamNames map (_ => TypeBounds.empty)
    val ptype = PolyType(tparamNames)(_ => tparamBounds, resultTypeFn)
    newMethod(cls, name, ptype, flags)
  }

  private def newT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
    newPolyMethod(cls, name, 1, resultTypeFn, flags)

  private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
    newPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags)

  private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[ClassSymbol] = {
    val arr = new Array[ClassSymbol](arity + 1)
    for (i <- countFrom to arity) arr(i) = ctx.requiredClass(name + i)
    arr
  }

  private def completeClass(cls: ClassSymbol): ClassSymbol = {
    ensureConstructor(cls, EmptyScope)
    if (cls.linkedClass.exists) cls.linkedClass.info = NoType
    cls
  }

  lazy val RootClass: ClassSymbol = ctx.newPackageSymbol(
    NoSymbol, nme.ROOT, (root, rootcls) => ctx.rootLoader(root)).moduleClass.asClass
  lazy val RootPackage: TermSymbol = ctx.newSymbol(
    NoSymbol, nme.ROOTPKG, PackageCreationFlags, TypeRef(NoPrefix, RootClass))

  lazy val EmptyPackageClass = ctx.newCompletePackageSymbol(RootClass, nme.EMPTY_PACKAGE).moduleClass.asClass
  lazy val EmptyPackageVal = EmptyPackageClass.sourceModule.entered

  lazy val ScalaPackageVal = ctx.requiredPackage("scala")
  lazy val ScalaMathPackageVal = ctx.requiredPackage("scala.math")
  lazy val ScalaPackageClass = ScalaPackageVal.moduleClass.asClass
  lazy val JavaPackageVal = ctx.requiredPackage("java")
  lazy val JavaLangPackageVal = ctx.requiredPackage("java.lang")
  // fundamental modules
  lazy val SysPackage = ctx.requiredModule("scala.sys.package")
    def Sys_error = ctx.requiredMethod(SysPackage.moduleClass.asClass, nme.error)

  /** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter)
   *  because after erasure the Any and AnyVal references get remapped to the Object methods
   *  which would result in a double binding assertion failure.
   * Instead we do the following:
   *
   *  - Have some methods exist only in Any, and remap them with the Erasure denotation
   *    transformer to be owned by Object.
   *  - Have other methods exist only in Object.
   * To achieve this, we synthesize all Any and Object methods; Object methods no longer get
   * loaded from a classfile.
   *
   * There's a remaining question about `getClass`. In Scala2.x `getClass` was handled by compiler magic.
   * This is deemed too cumersome for Dotty and therefore right now `getClass` gets no special treatment;
   * it's just a method on `Any` which returns the raw type `java.lang.Class`. An alternative
   * way to get better `getClass` typing would be to treat `getClass` as a method of a generic
   * decorator which gets remapped in a later phase to Object#getClass. Then we could give it
   * the right type without changing the typechecker:
   *
   *     implicit class AnyGetClass[T](val x: T) extends AnyVal {
   *       def getClass: java.lang.Class[T] = ???
   *     }
   */
  lazy val AnyClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil))
  lazy val AnyValClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.AnyVal, Abstract, List(AnyClass.typeRef)))

    lazy val Any_==       = newMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final)
    lazy val Any_!=       = newMethod(AnyClass, nme.NE, methOfAny(BooleanType), Final)
    lazy val Any_equals   = newMethod(AnyClass, nme.equals_, methOfAny(BooleanType))
    lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, MethodType(Nil, IntType))
    lazy val Any_toString = newMethod(AnyClass, nme.toString_, MethodType(Nil, StringType))
    lazy val Any_##       = newMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final)
    lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef), Final)
    lazy val Any_isInstanceOf = newT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
    lazy val Any_asInstanceOf = newT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, PolyParam(_, 0), Final)

    def AnyMethods = List(Any_==, Any_!=, Any_equals, Any_hashCode,
      Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf)

  lazy val ObjectClass: ClassSymbol = {
    val cls = ctx.requiredClass("java.lang.Object")
    assert(!cls.isCompleted, "race for completing java.lang.Object")
    cls.info = ClassInfo(cls.owner.thisType, cls, AnyClass.typeRef :: Nil, newScope)
    completeClass(cls)
  }
  lazy val AnyRefAlias: TypeSymbol = newAliasType(tpnme.AnyRef, ObjectType)

    lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
    lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
    lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1,
        pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final)
    lazy val Object_clone = newMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected)
    lazy val Object_finalize = newMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected)
    lazy val Object_notify = newMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType))
    lazy val Object_notifyAll = newMethod(ObjectClass, nme.notifyAll_, MethodType(Nil, UnitType))
    lazy val Object_wait = newMethod(ObjectClass, nme.wait_, MethodType(Nil, UnitType))
    lazy val Object_waitL = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: Nil, UnitType))
    lazy val Object_waitLI = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: IntType :: Nil, UnitType))

    def ObjectMethods = List(Object_eq, Object_ne, Object_synchronized, Object_clone,
        Object_finalize, Object_notify, Object_notifyAll, Object_wait, Object_waitL, Object_waitLI)

  lazy val NotNullClass = ctx.requiredClass("scala.NotNull")

  lazy val NothingClass: ClassSymbol = newCompleteClassSymbol(
    ScalaPackageClass, tpnme.Nothing, AbstractFinal, List(AnyClass.typeRef))
  lazy val NullClass: ClassSymbol = newCompleteClassSymbol(
    ScalaPackageClass, tpnme.Null, AbstractFinal, List(ObjectClass.typeRef))

  lazy val ScalaPredefModule = ctx.requiredModule("scala.Predef")
  lazy val ScalaRuntimeModule = ctx.requiredModule("scala.runtime.ScalaRunTime")
  lazy val ScalaRuntimeClass = ScalaRuntimeModule.moduleClass.asClass

    def runtimeMethod(name: PreName) = ctx.requiredMethod(ScalaRuntimeClass, name)

  lazy val BoxesRunTimeModule = ctx.requiredModule("scala.runtime.BoxesRunTime")
  lazy val BoxesRunTimeClass = BoxesRunTimeModule.moduleClass.asClass
  lazy val ScalaStaticsModule = ctx.requiredModule("scala.runtime.Statics")
  lazy val ScalaStaticsClass = ScalaStaticsModule.moduleClass.asClass

    def staticsMethod(name: PreName) = ctx.requiredMethod(ScalaStaticsClass, name)

  lazy val DottyPredefModule = ctx.requiredModule("dotty.DottyPredef")
  lazy val DottyArraysModule = ctx.requiredModule("dotty.runtime.Arrays")

    def newRefArrayMethod = ctx.requiredMethod(DottyArraysModule.moduleClass.asClass, "newRefArray")

  lazy val NilModule = ctx.requiredModule("scala.collection.immutable.Nil")
  lazy val PredefConformsClass = ctx.requiredClass("scala.Predef." + tpnme.Conforms)

//  lazy val FunctionClass: ClassSymbol = ctx.requiredClass("scala.Function")
  lazy val SingletonClass: ClassSymbol =
    // needed as a synthetic class because Scala 2.x refers to it in classfiles
    // but does not define it as an explicit class.
    newCompleteClassSymbol(
      ScalaPackageClass, tpnme.Singleton, PureInterfaceCreationFlags | Final,
      List(AnyClass.typeRef), EmptyScope)
  lazy val SeqClass: ClassSymbol = ctx.requiredClass("scala.collection.Seq")
    lazy val Seq_apply = ctx.requiredMethod(SeqClass, nme.apply)
    lazy val Seq_head = ctx.requiredMethod(SeqClass, nme.head)
  lazy val ArrayClass: ClassSymbol = ctx.requiredClass("scala.Array")
    lazy val Array_apply                 = ctx.requiredMethod(ArrayClass, nme.apply)
    lazy val Array_update                = ctx.requiredMethod(ArrayClass, nme.update)
    lazy val Array_length                = ctx.requiredMethod(ArrayClass, nme.length)
    lazy val Array_clone                 = ctx.requiredMethod(ArrayClass, nme.clone_)
    lazy val ArrayConstructor            = ctx.requiredMethod(ArrayClass, nme.CONSTRUCTOR)
  lazy val traversableDropMethod  = ctx.requiredMethod(ScalaRuntimeClass, nme.drop)
  lazy val uncheckedStableClass: ClassSymbol = ctx.requiredClass("scala.annotation.unchecked.uncheckedStable")

  lazy val UnitClass = valueClassSymbol("scala.Unit", BoxedUnitClass, java.lang.Void.TYPE, UnitEnc)
  lazy val BooleanClass = valueClassSymbol("scala.Boolean", BoxedBooleanClass, java.lang.Boolean.TYPE, BooleanEnc)
    lazy val Boolean_!   = BooleanClass.requiredMethod(nme.UNARY_!)
    lazy val Boolean_&& = BooleanClass.requiredMethod(nme.ZAND)
    lazy val Boolean_||  = BooleanClass.requiredMethod(nme.ZOR)

  lazy val ByteClass = valueClassSymbol("scala.Byte", BoxedByteClass, java.lang.Byte.TYPE, ByteEnc)
  lazy val ShortClass = valueClassSymbol("scala.Short", BoxedShortClass, java.lang.Short.TYPE, ShortEnc)
  lazy val CharClass = valueClassSymbol("scala.Char", BoxedCharClass, java.lang.Character.TYPE, CharEnc)
  lazy val IntClass = valueClassSymbol("scala.Int", BoxedIntClass, java.lang.Integer.TYPE, IntEnc)
    lazy val Int_-   = IntClass.requiredMethod(nme.MINUS, List(IntType))
    lazy val Int_+   = IntClass.requiredMethod(nme.PLUS, List(IntType))
    lazy val Int_/   = IntClass.requiredMethod(nme.DIV, List(IntType))
    lazy val Int_*   = IntClass.requiredMethod(nme.MUL, List(IntType))
    lazy val Int_==   = IntClass.requiredMethod(nme.EQ, List(IntType))
    lazy val Int_>=   = IntClass.requiredMethod(nme.GE, List(IntType))
    lazy val Int_<=   = IntClass.requiredMethod(nme.LE, List(IntType))
  lazy val LongClass = valueClassSymbol("scala.Long", BoxedLongClass, java.lang.Long.TYPE, LongEnc)
    lazy val Long_XOR_Long = LongClass.info.member(nme.XOR).requiredSymbol(
      x => (x is Method) && (x.info.firstParamTypes.head isRef defn.LongClass)
    )
    lazy val Long_LSR_Int = LongClass.info.member(nme.LSR).requiredSymbol(
      x => (x is Method) && (x.info.firstParamTypes.head isRef defn.IntClass)
    )
  lazy val FloatClass = valueClassSymbol("scala.Float", BoxedFloatClass, java.lang.Float.TYPE, FloatEnc)
  lazy val DoubleClass = valueClassSymbol("scala.Double", BoxedDoubleClass, java.lang.Double.TYPE, DoubleEnc)

  lazy val BoxedUnitClass = ctx.requiredClass("scala.runtime.BoxedUnit")

    lazy val BoxedUnit_UNIT = BoxedUnitClass.linkedClass.requiredValue("UNIT")

  lazy val BoxedBooleanClass = ctx.requiredClass("java.lang.Boolean")
  lazy val BoxedByteClass = ctx.requiredClass("java.lang.Byte")
  lazy val BoxedShortClass = ctx.requiredClass("java.lang.Short")
  lazy val BoxedCharClass = ctx.requiredClass("java.lang.Character")
  lazy val BoxedIntClass = ctx.requiredClass("java.lang.Integer")
  lazy val BoxedLongClass = ctx.requiredClass("java.lang.Long")
  lazy val BoxedFloatClass = ctx.requiredClass("java.lang.Float")
  lazy val BoxedDoubleClass = ctx.requiredClass("java.lang.Double")

  lazy val ByNameParamClass2x     = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, AnyType)
  lazy val EqualsPatternClass     = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, AnyType)

  lazy val RepeatedParamClass     = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, SeqType)

  // fundamental classes
  lazy val StringClass                  = ctx.requiredClass("java.lang.String")
  lazy val StringModule                 = StringClass.moduleClass

    lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, methOfAny(StringType), Final)
    lazy val String_valueOf_Object = StringModule.info.member(nme.valueOf).suchThat(_.info.firstParamTypes match {
      case List(pt) => pt isRef ObjectClass
      case _ => false
    }).symbol

  // in scalac modified to have Any as parrent

  lazy val SerializableClass         = ctx.requiredClass("scala.Serializable")
  lazy val JavaCloneableClass        = ctx.requiredClass("java.lang.Cloneable")
  lazy val StringBuilderClass        = ctx.requiredClass("scala.collection.mutable.StringBuilder")
  lazy val NullPointerExceptionClass = ctx.requiredClass(jnme.NPException)
  lazy val MatchErrorClass           = ctx.requiredClass("scala.MatchError")
  lazy val MatchErrorType            = MatchErrorClass.typeRef

  lazy val StringAddClass               = ctx.requiredClass("scala.runtime.StringAdd")

    lazy val StringAdd_+ = StringAddClass.requiredMethod(nme.raw.PLUS)

  lazy val PairClass                    = ctx.requiredClass("dotty.Pair")
  lazy val PartialFunctionClass         = ctx.requiredClass("scala.PartialFunction")
  lazy val AbstractPartialFunctionClass = ctx.requiredClass("scala.runtime.AbstractPartialFunction")
  lazy val SymbolClass                  = ctx.requiredClass("scala.Symbol")
  lazy val ClassClass                   = ctx.requiredClass("java.lang.Class")
  lazy val DynamicClass                 = ctx.requiredClass("scala.Dynamic")
  lazy val OptionClass                  = ctx.requiredClass("scala.Option")
  lazy val BoxedNumberClass             = ctx.requiredClass("java.lang.Number")
  lazy val ThrowableClass               = ctx.requiredClass("java.lang.Throwable")
  lazy val ClassCastExceptionClass      = ctx.requiredClass("java.lang.ClassCastException")
  lazy val JavaSerializableClass        = ctx.requiredClass("java.lang.Serializable")
  lazy val ComparableClass              = ctx.requiredClass("java.lang.Comparable")
  lazy val ProductClass                 = ctx.requiredClass("scala.Product")
    lazy val Product_canEqual = ProductClass.requiredMethod(nme.canEqual_)
    lazy val Product_productArity = ProductClass.requiredMethod(nme.productArity)
  lazy val LanguageModuleClass          = ctx.requiredModule("dotty.language").moduleClass.asClass

  // Annotation base classes
  lazy val AnnotationClass              = ctx.requiredClass("scala.annotation.Annotation")
  lazy val ClassfileAnnotationClass     = ctx.requiredClass("scala.annotation.ClassfileAnnotation")
  lazy val StaticAnnotationClass        = ctx.requiredClass("scala.annotation.StaticAnnotation")
  lazy val TailrecAnnotationClass       = ctx.requiredClass("scala.annotation.tailrec")
  lazy val RemoteAnnot                   = ctx.requiredClass("scala.remote")
  lazy val SerialVersionUIDAnnot         = ctx.requiredClass("scala.SerialVersionUID")
  lazy val TransientAnnot                = ctx.requiredClass("scala.transient")
  lazy val NativeAnnot                   = ctx.requiredClass("scala.native")
  lazy val ScalaStrictFPAnnot            = ctx.requiredClass("scala.annotation.strictfp")

  // Annotation classes
  lazy val AliasAnnot = ctx.requiredClass("dotty.annotation.internal.Alias")
  lazy val ChildAnnot = ctx.requiredClass("dotty.annotation.internal.Child")
  lazy val RepeatedAnnot = ctx.requiredClass("dotty.annotation.internal.Repeated")
  lazy val InvariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.InvariantBetween")
  lazy val CovariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.CovariantBetween")
  lazy val ContravariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.ContravariantBetween")
  lazy val ScalaSignatureAnnot = ctx.requiredClass("scala.reflect.ScalaSignature")
  lazy val ScalaLongSignatureAnnot = ctx.requiredClass("scala.reflect.ScalaLongSignature")
  lazy val DeprecatedAnnot = ctx.requiredClass("scala.deprecated")
  lazy val MigrationAnnot = ctx.requiredClass("scala.annotation.migration")
  lazy val AnnotationDefaultAnnot = ctx.requiredClass("dotty.annotation.internal.AnnotationDefault")
  lazy val ThrowsAnnot = ctx.requiredClass("scala.throws")
  lazy val UncheckedAnnot = ctx.requiredClass("scala.unchecked")
  lazy val UncheckedStableAnnot = ctx.requiredClass("scala.annotation.unchecked.uncheckedStable")
  lazy val UncheckedVarianceAnnot = ctx.requiredClass("scala.annotation.unchecked.uncheckedVariance")
  lazy val VolatileAnnot = ctx.requiredClass("scala.volatile")

  // convenient one-parameter method types
  def methOfAny(tp: Type) = MethodType(List(AnyType), tp)
  def methOfAnyVal(tp: Type) = MethodType(List(AnyValType), tp)
  def methOfAnyRef(tp: Type) = MethodType(List(ObjectType), tp)

  // Derived types
  def AnyType: Type = AnyClass.typeRef
  def AnyValType: Type = AnyValClass.typeRef
  def ObjectType: Type = ObjectClass.typeRef
  def AnyRefType: Type = AnyRefAlias.typeRef
  def NotNullType: Type = NotNullClass.typeRef
  def NothingType: Type = NothingClass.typeRef
  def NullType: Type = NullClass.typeRef
  def SeqType: Type = SeqClass.typeRef

  def UnitType: Type = UnitClass.typeRef
  def BooleanType: Type = BooleanClass.typeRef
  def ByteType: Type = ByteClass.typeRef
  def ShortType: Type = ShortClass.typeRef
  def CharType: Type = CharClass.typeRef
  def IntType: Type = IntClass.typeRef
  def LongType: Type = LongClass.typeRef
  def FloatType: Type = FloatClass.typeRef
  def DoubleType: Type = DoubleClass.typeRef
  def PairType: Type = PairClass.typeRef
  def StringType: Type = StringClass.typeRef
  def RepeatedParamType = RepeatedParamClass.typeRef
  def ThrowableType = ThrowableClass.typeRef
  def OptionType = OptionClass.typeRef
  def VolatileAnnotType = VolatileAnnot.typeRef

  def ClassType(arg: Type)(implicit ctx: Context) = {
    val ctype = ClassClass.typeRef
    if (ctx.phase.erasedTypes) ctype else ctype.appliedTo(arg)
  }

  /** The enumeration type, goven a value of the enumeration */
  def EnumType(sym: Symbol)(implicit ctx: Context) =
    // given (in java): "class A { enum E { VAL1 } }"
    //  - sym: the symbol of the actual enumeration value (VAL1)
    //  - .owner: the ModuleClassSymbol of the enumeration (object E)
    //  - .linkedClass: the ClassSymbol of the enumeration (class E)
    sym.owner.linkedClass.typeRef

  object FunctionType {
    def apply(args: List[Type], resultType: Type)(implicit ctx: Context) =
      FunctionClass(args.length).typeRef.appliedTo(args ::: resultType :: Nil)
    def unapply(ft: Type)(implicit ctx: Context)/*: Option[(List[Type], Type)]*/ = {
      // -language:keepUnions difference: unapply needs result type because inferred type
      // is Some[(List[Type], Type)] | None, which is not a legal unapply type.
      val tsym = ft.typeSymbol
      lazy val targs = ft.argInfos
      if ((FunctionClasses contains tsym) &&
          (targs.length - 1 <= MaxFunctionArity) &&
          (FunctionClass(targs.length - 1) == tsym)) Some(targs.init, targs.last)
      else None
    }
  }

  object ArrayType {
    def apply(elem: Type)(implicit ctx: Context) =
      ArrayClass.typeRef.appliedTo(elem :: Nil)
    def unapply(tp: Type)(implicit ctx: Context) = tp.dealias match {
      case at: RefinedType if (at isRef ArrayClass) && at.argInfos.length == 1 => Some(at.argInfos.head)
      case _ => None
    }
  }

  object MultiArrayType {
    def apply(elem: Type, ndims: Int)(implicit ctx: Context): Type =
      if (ndims == 0) elem else ArrayType(apply(elem, ndims - 1))
    def unapply(tp: Type)(implicit ctx: Context): Option[(Type, Int)] = tp match {
      case ArrayType(elemtp) =>
        elemtp match {
          case MultiArrayType(finalElemTp, n) => Some(finalElemTp, n + 1)
          case _ => Some(elemtp, 1)
        }
      case _ =>
        None
    }
  }

  // ----- Symbol sets ---------------------------------------------------

  lazy val AbstractFunctionClass = mkArityArray("scala.runtime.AbstractFunction", MaxFunctionArity, 0)
  lazy val FunctionClass = mkArityArray("scala.Function", MaxFunctionArity, 0)
    lazy val Function0_apply = FunctionClass(0).requiredMethod(nme.apply)

  lazy val TupleClass = mkArityArray("scala.Tuple", MaxTupleArity, 2)
  lazy val ProductNClass = mkArityArray("scala.Product", MaxTupleArity, 0)

  lazy val FunctionClasses: Set[Symbol] = FunctionClass.toSet
  lazy val TupleClasses: Set[Symbol] = TupleClass.toSet
  lazy val ProductClasses: Set[Symbol] = ProductNClass.toSet

  /** `Modules whose members are in the default namespace and their module classes */
  lazy val UnqualifiedOwners = RootImports.toSet ++ RootImports.map(_.moduleClass)

  lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)

  lazy val isPolymorphicAfterErasure = Set[Symbol](Any_isInstanceOf, Any_asInstanceOf, newRefArrayMethod)

  lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)

  lazy val overriddenBySynthetic = Set[Symbol](Any_equals, Any_hashCode, Any_toString, Product_canEqual)
  def isTupleType(tp: Type)(implicit ctx: Context) = {
    val arity = tp.dealias.argInfos.length
    arity <= MaxTupleArity && (tp isRef TupleClass(arity))
  }

  def tupleType(elems: List[Type]) = {
    TupleClass(elems.size).typeRef.appliedTo(elems)
  }

  def isProductSubType(tp: Type)(implicit ctx: Context) =
    (tp derivesFrom ProductClass) && tp.baseClasses.exists(ProductClasses contains _)

  def isFunctionType(tp: Type)(implicit ctx: Context) = {
    val arity = functionArity(tp)
    0 <= arity && arity <= MaxFunctionArity && (tp isRef FunctionClass(arity))
  }

  def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1

  // ----- LambdaXYZ traits ------------------------------------------

  private var myLambdaTraits: Set[Symbol] = Set()

  /** The set of HigherKindedXYZ traits encountered so far */
  def lambdaTraits: Set[Symbol] = myLambdaTraits

  private var lambdaTraitForVariances = mutable.Map[List[Int], ClassSymbol]()

  /** The HigherKinded trait corresponding to symbols `boundSyms` (which are assumed
   *  to be the type parameters of a higher-kided type). This is a class symbol that
   *  would be generated by the following schema.
   *
   *      class LambdaXYZ extends Object with P1 with ... with Pn {
   *        type v_1 $hk$Arg0; ...; type v_N $hk$ArgN;
   *        type Apply
   *      }
   *
   *  Here:
   *
   *   - v_i are the variances of the bound symbols (i.e. +, -, or empty).
   *   - XYZ is a string of length N with one letter for each variant of a bound symbol,
   *     using `P` (positive variance), `N` (negative variance), `I` (invariant).
   *   - for each positive or negative variance v_i there is a parent trait Pj which
   *     is the same as LambdaXYZ except that it has `I` in i-th position.
   */
  def lambdaTrait(vcs: List[Int]): ClassSymbol = {
    assert(vcs.nonEmpty)

    def varianceFlags(v: Int) = v match {
      case -1 => Contravariant
      case  0 => EmptyFlags
      case  1 => Covariant
    }

    val completer = new LazyType  {
      def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
        val cls = denot.asClass.classSymbol
        val paramDecls = newScope
        for (i <- 0 until vcs.length)
          newTypeParam(cls, tpnme.lambdaArgName(i), varianceFlags(vcs(i)), paramDecls)
        newTypeField(cls, tpnme.Apply, Covariant, paramDecls)
        val parentTraitRefs =
          for (i <- 0 until vcs.length if vcs(i) != 0)
          yield lambdaTrait(vcs.updated(i, 0)).typeRef
        denot.info = ClassInfo(
            ScalaPackageClass.thisType, cls, ObjectClass.typeRef :: parentTraitRefs.toList, paramDecls)
      }
    }

    val traitName = tpnme.lambdaTraitName(vcs)

    def createTrait = {
      val cls = newClassSymbol(
        ScalaPackageClass,
        traitName,
        PureInterfaceCreationFlags | Synthetic,
        completer)
      myLambdaTraits += cls
      cls
    }

    lambdaTraitForVariances.getOrElseUpdate(vcs, createTrait)
  }

  // ----- primitive value class machinery ------------------------------------------

  lazy val ScalaNumericValueClasses: collection.Set[Symbol] =  Set(
    ByteClass,
    ShortClass,
    CharClass,
    IntClass,
    LongClass,
    FloatClass,
    DoubleClass)

  lazy val ScalaValueClasses: collection.Set[Symbol] = ScalaNumericValueClasses + UnitClass + BooleanClass

  lazy val ScalaBoxedClasses = ScalaValueClasses map boxedClass

  private[this] val _boxedClass = mutable.Map[Symbol, Symbol]()
  private[this] val _unboxedClass = mutable.Map[Symbol, Symbol]()

  private[this] val _javaTypeToValueClass = mutable.Map[Class[_], Symbol]()
  private[this] val _valueClassToJavaType = mutable.Map[Symbol, Class[_]]()
  private[this] val _valueClassEnc = mutable.Map[Symbol, Int]()

  val boxedClass: collection.Map[Symbol, Symbol] = _boxedClass
  val unboxedClass: collection.Map[Symbol, Symbol] = _boxedClass
  val javaTypeToValueClass: collection.Map[Class[_], Symbol] = _javaTypeToValueClass
  val valueClassToJavaType: collection.Map[Symbol, Class[_]] = _valueClassToJavaType
  val valueClassEnc: collection.Map[Symbol, Int] = _valueClassEnc

  private def valueClassSymbol(name: String, boxed: ClassSymbol, jtype: Class[_], enc: Int): ClassSymbol = {
    val vcls = ctx.requiredClass(name)
    _unboxedClass(boxed) = vcls
    _boxedClass(vcls) = boxed
    _javaTypeToValueClass(jtype) = vcls
    _valueClassToJavaType(vcls) = jtype
    _valueClassEnc(vcls) = enc
    vcls
  }

  /** The classes for which a Ref type exists. */
  lazy val refClasses: collection.Set[Symbol] = ScalaNumericValueClasses + BooleanClass + ObjectClass

  lazy val refClass: Map[Symbol, Symbol] =
    refClasses.map(rc => rc -> ctx.requiredClass(s"scala.runtime.${rc.name}Ref")).toMap

  lazy val volatileRefClass: Map[Symbol, Symbol] =
    refClasses.map(rc => rc -> ctx.requiredClass(s"scala.runtime.Volatile${rc.name}Ref")).toMap

  def wrapArrayMethodName(elemtp: Type): TermName = {
    val cls = elemtp.classSymbol
    if (cls.isPrimitiveValueClass) nme.wrapXArray(cls.name)
    else if (cls.derivesFrom(ObjectClass) && !cls.isPhantomClass) nme.wrapRefArray
    else nme.genericWrapArray
  }

  val ByteEnc = 2
  val ShortEnc = ByteEnc * 3
  val CharEnc = 5
  val IntEnc = ShortEnc * CharEnc
  val LongEnc = IntEnc * 7
  val FloatEnc = LongEnc * 11
  val DoubleEnc = FloatEnc * 13
  val BooleanEnc = 17
  val UnitEnc = 19

  def isValueSubClass(cls1: Symbol, cls2: Symbol)(implicit ctx: Context) =
    valueClassEnc(cls2) % valueClassEnc(cls1) == 0

  // ----- Initialization ---------------------------------------------------

  /** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
  lazy val syntheticCoreClasses = List(
    AnyClass,
    AnyRefAlias,
    RepeatedParamClass,
    ByNameParamClass2x,
    AnyValClass,
    NullClass,
    NothingClass,
    SingletonClass,
    EqualsPatternClass,
    EmptyPackageVal)

    /** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
    lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+)

  private[this] var _isInitialized = false
  def isInitialized = _isInitialized

  def init(implicit ctx: Context) = {
    this.ctx = ctx
    if (!_isInitialized) {
      // force initialization of every symbol that is synthesized or hijacked by the compiler
      val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses
      _isInitialized = true
    }
  }
}
<commit_msg>made ArrayType constructor phase aware<commit_after>package dotty.tools
package dotc
package core

import Types._, Contexts._, Symbols._, Denotations._, SymDenotations._, StdNames._, Names._
import Flags._, Scopes._, Decorators._, NameOps._, util.Positions._
import pickling.UnPickler.ensureConstructor
import scala.annotation.{ switch, meta }
import scala.collection.{ mutable, immutable }
import PartialFunction._
import collection.mutable
import scala.reflect.api.{ Universe => ApiUniverse }

object Definitions {
  val MaxFunctionArity, MaxTupleArity = 22
}

/** A class defining symbols and types of standard definitions */
class Definitions {
  import Definitions._

  private implicit var ctx: Context = _

  private def newSymbol[N <: Name](owner: Symbol, name: N, flags: FlagSet, info: Type) =
    ctx.newSymbol(owner, name, flags | Permanent, info)

  private def newClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, infoFn: ClassSymbol => Type) =
    ctx.newClassSymbol(owner, name, flags | Permanent, infoFn).entered

  private def newCompleteClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, parents: List[TypeRef], decls: Scope = newScope) =
    ctx.newCompleteClassSymbol(owner, name, flags | Permanent, parents, decls).entered

  private def newTopClassSymbol(name: TypeName, flags: FlagSet, parents: List[TypeRef]) =
    completeClass(newCompleteClassSymbol(ScalaPackageClass, name, flags, parents))

  private def newTypeField(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
    scope.enter(newSymbol(cls, name, flags, TypeBounds.empty))

  private def newTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
    newTypeField(cls, name, flags | ClassTypeParamCreationFlags, scope)

  private def newSyntheticTypeParam(cls: ClassSymbol, scope: MutableScope, paramFlags: FlagSet, suffix: String = "T0") =
    newTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope)

  private def specialPolyClass(name: TypeName, paramFlags: FlagSet, parentConstrs: Type*): ClassSymbol = {
    val completer = new LazyType {
      def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
        val cls = denot.asClass.classSymbol
        val paramDecls = newScope
        val typeParam = newSyntheticTypeParam(cls, paramDecls, paramFlags)
        def instantiate(tpe: Type) =
          if (tpe.typeParams.nonEmpty) tpe.appliedTo(typeParam.typeRef)
          else tpe
        val parents = parentConstrs.toList map instantiate
        val parentRefs: List[TypeRef] = ctx.normalizeToClassRefs(parents, cls, paramDecls)
        denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parentRefs, paramDecls)
      }
    }
    newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer)
  }

  private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol =
    newSymbol(cls, name.encode, flags | Method, info).entered.asTerm

  private def newAliasType(name: TypeName, tpe: Type, flags: FlagSet = EmptyFlags): TypeSymbol = {
    val sym = newSymbol(ScalaPackageClass, name, flags, TypeAlias(tpe))
    ScalaPackageClass.preDecls.enter(sym)
    sym
  }

  private def newPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int,
                    resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = {
    val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount)
    val tparamBounds = tparamNames map (_ => TypeBounds.empty)
    val ptype = PolyType(tparamNames)(_ => tparamBounds, resultTypeFn)
    newMethod(cls, name, ptype, flags)
  }

  private def newT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
    newPolyMethod(cls, name, 1, resultTypeFn, flags)

  private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
    newPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags)

  private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[ClassSymbol] = {
    val arr = new Array[ClassSymbol](arity + 1)
    for (i <- countFrom to arity) arr(i) = ctx.requiredClass(name + i)
    arr
  }

  private def completeClass(cls: ClassSymbol): ClassSymbol = {
    ensureConstructor(cls, EmptyScope)
    if (cls.linkedClass.exists) cls.linkedClass.info = NoType
    cls
  }

  lazy val RootClass: ClassSymbol = ctx.newPackageSymbol(
    NoSymbol, nme.ROOT, (root, rootcls) => ctx.rootLoader(root)).moduleClass.asClass
  lazy val RootPackage: TermSymbol = ctx.newSymbol(
    NoSymbol, nme.ROOTPKG, PackageCreationFlags, TypeRef(NoPrefix, RootClass))

  lazy val EmptyPackageClass = ctx.newCompletePackageSymbol(RootClass, nme.EMPTY_PACKAGE).moduleClass.asClass
  lazy val EmptyPackageVal = EmptyPackageClass.sourceModule.entered

  lazy val ScalaPackageVal = ctx.requiredPackage("scala")
  lazy val ScalaMathPackageVal = ctx.requiredPackage("scala.math")
  lazy val ScalaPackageClass = ScalaPackageVal.moduleClass.asClass
  lazy val JavaPackageVal = ctx.requiredPackage("java")
  lazy val JavaLangPackageVal = ctx.requiredPackage("java.lang")
  // fundamental modules
  lazy val SysPackage = ctx.requiredModule("scala.sys.package")
    def Sys_error = ctx.requiredMethod(SysPackage.moduleClass.asClass, nme.error)

  /** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter)
   *  because after erasure the Any and AnyVal references get remapped to the Object methods
   *  which would result in a double binding assertion failure.
   * Instead we do the following:
   *
   *  - Have some methods exist only in Any, and remap them with the Erasure denotation
   *    transformer to be owned by Object.
   *  - Have other methods exist only in Object.
   * To achieve this, we synthesize all Any and Object methods; Object methods no longer get
   * loaded from a classfile.
   *
   * There's a remaining question about `getClass`. In Scala2.x `getClass` was handled by compiler magic.
   * This is deemed too cumersome for Dotty and therefore right now `getClass` gets no special treatment;
   * it's just a method on `Any` which returns the raw type `java.lang.Class`. An alternative
   * way to get better `getClass` typing would be to treat `getClass` as a method of a generic
   * decorator which gets remapped in a later phase to Object#getClass. Then we could give it
   * the right type without changing the typechecker:
   *
   *     implicit class AnyGetClass[T](val x: T) extends AnyVal {
   *       def getClass: java.lang.Class[T] = ???
   *     }
   */
  lazy val AnyClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil))
  lazy val AnyValClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.AnyVal, Abstract, List(AnyClass.typeRef)))

    lazy val Any_==       = newMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final)
    lazy val Any_!=       = newMethod(AnyClass, nme.NE, methOfAny(BooleanType), Final)
    lazy val Any_equals   = newMethod(AnyClass, nme.equals_, methOfAny(BooleanType))
    lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, MethodType(Nil, IntType))
    lazy val Any_toString = newMethod(AnyClass, nme.toString_, MethodType(Nil, StringType))
    lazy val Any_##       = newMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final)
    lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef), Final)
    lazy val Any_isInstanceOf = newT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
    lazy val Any_asInstanceOf = newT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, PolyParam(_, 0), Final)

    def AnyMethods = List(Any_==, Any_!=, Any_equals, Any_hashCode,
      Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf)

  lazy val ObjectClass: ClassSymbol = {
    val cls = ctx.requiredClass("java.lang.Object")
    assert(!cls.isCompleted, "race for completing java.lang.Object")
    cls.info = ClassInfo(cls.owner.thisType, cls, AnyClass.typeRef :: Nil, newScope)
    completeClass(cls)
  }
  lazy val AnyRefAlias: TypeSymbol = newAliasType(tpnme.AnyRef, ObjectType)

    lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
    lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
    lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1,
        pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final)
    lazy val Object_clone = newMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected)
    lazy val Object_finalize = newMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected)
    lazy val Object_notify = newMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType))
    lazy val Object_notifyAll = newMethod(ObjectClass, nme.notifyAll_, MethodType(Nil, UnitType))
    lazy val Object_wait = newMethod(ObjectClass, nme.wait_, MethodType(Nil, UnitType))
    lazy val Object_waitL = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: Nil, UnitType))
    lazy val Object_waitLI = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: IntType :: Nil, UnitType))

    def ObjectMethods = List(Object_eq, Object_ne, Object_synchronized, Object_clone,
        Object_finalize, Object_notify, Object_notifyAll, Object_wait, Object_waitL, Object_waitLI)

  lazy val NotNullClass = ctx.requiredClass("scala.NotNull")

  lazy val NothingClass: ClassSymbol = newCompleteClassSymbol(
    ScalaPackageClass, tpnme.Nothing, AbstractFinal, List(AnyClass.typeRef))
  lazy val NullClass: ClassSymbol = newCompleteClassSymbol(
    ScalaPackageClass, tpnme.Null, AbstractFinal, List(ObjectClass.typeRef))

  lazy val ScalaPredefModule = ctx.requiredModule("scala.Predef")
  lazy val ScalaRuntimeModule = ctx.requiredModule("scala.runtime.ScalaRunTime")
  lazy val ScalaRuntimeClass = ScalaRuntimeModule.moduleClass.asClass

    def runtimeMethod(name: PreName) = ctx.requiredMethod(ScalaRuntimeClass, name)

  lazy val BoxesRunTimeModule = ctx.requiredModule("scala.runtime.BoxesRunTime")
  lazy val BoxesRunTimeClass = BoxesRunTimeModule.moduleClass.asClass
  lazy val ScalaStaticsModule = ctx.requiredModule("scala.runtime.Statics")
  lazy val ScalaStaticsClass = ScalaStaticsModule.moduleClass.asClass

    def staticsMethod(name: PreName) = ctx.requiredMethod(ScalaStaticsClass, name)

  lazy val DottyPredefModule = ctx.requiredModule("dotty.DottyPredef")
  lazy val DottyArraysModule = ctx.requiredModule("dotty.runtime.Arrays")

    def newRefArrayMethod = ctx.requiredMethod(DottyArraysModule.moduleClass.asClass, "newRefArray")

  lazy val NilModule = ctx.requiredModule("scala.collection.immutable.Nil")
  lazy val PredefConformsClass = ctx.requiredClass("scala.Predef." + tpnme.Conforms)

//  lazy val FunctionClass: ClassSymbol = ctx.requiredClass("scala.Function")
  lazy val SingletonClass: ClassSymbol =
    // needed as a synthetic class because Scala 2.x refers to it in classfiles
    // but does not define it as an explicit class.
    newCompleteClassSymbol(
      ScalaPackageClass, tpnme.Singleton, PureInterfaceCreationFlags | Final,
      List(AnyClass.typeRef), EmptyScope)
  lazy val SeqClass: ClassSymbol = ctx.requiredClass("scala.collection.Seq")
    lazy val Seq_apply = ctx.requiredMethod(SeqClass, nme.apply)
    lazy val Seq_head = ctx.requiredMethod(SeqClass, nme.head)
  lazy val ArrayClass: ClassSymbol = ctx.requiredClass("scala.Array")
    lazy val Array_apply                 = ctx.requiredMethod(ArrayClass, nme.apply)
    lazy val Array_update                = ctx.requiredMethod(ArrayClass, nme.update)
    lazy val Array_length                = ctx.requiredMethod(ArrayClass, nme.length)
    lazy val Array_clone                 = ctx.requiredMethod(ArrayClass, nme.clone_)
    lazy val ArrayConstructor            = ctx.requiredMethod(ArrayClass, nme.CONSTRUCTOR)
  lazy val traversableDropMethod  = ctx.requiredMethod(ScalaRuntimeClass, nme.drop)
  lazy val uncheckedStableClass: ClassSymbol = ctx.requiredClass("scala.annotation.unchecked.uncheckedStable")

  lazy val UnitClass = valueClassSymbol("scala.Unit", BoxedUnitClass, java.lang.Void.TYPE, UnitEnc)
  lazy val BooleanClass = valueClassSymbol("scala.Boolean", BoxedBooleanClass, java.lang.Boolean.TYPE, BooleanEnc)
    lazy val Boolean_!   = BooleanClass.requiredMethod(nme.UNARY_!)
    lazy val Boolean_&& = BooleanClass.requiredMethod(nme.ZAND)
    lazy val Boolean_||  = BooleanClass.requiredMethod(nme.ZOR)

  lazy val ByteClass = valueClassSymbol("scala.Byte", BoxedByteClass, java.lang.Byte.TYPE, ByteEnc)
  lazy val ShortClass = valueClassSymbol("scala.Short", BoxedShortClass, java.lang.Short.TYPE, ShortEnc)
  lazy val CharClass = valueClassSymbol("scala.Char", BoxedCharClass, java.lang.Character.TYPE, CharEnc)
  lazy val IntClass = valueClassSymbol("scala.Int", BoxedIntClass, java.lang.Integer.TYPE, IntEnc)
    lazy val Int_-   = IntClass.requiredMethod(nme.MINUS, List(IntType))
    lazy val Int_+   = IntClass.requiredMethod(nme.PLUS, List(IntType))
    lazy val Int_/   = IntClass.requiredMethod(nme.DIV, List(IntType))
    lazy val Int_*   = IntClass.requiredMethod(nme.MUL, List(IntType))
    lazy val Int_==   = IntClass.requiredMethod(nme.EQ, List(IntType))
    lazy val Int_>=   = IntClass.requiredMethod(nme.GE, List(IntType))
    lazy val Int_<=   = IntClass.requiredMethod(nme.LE, List(IntType))
  lazy val LongClass = valueClassSymbol("scala.Long", BoxedLongClass, java.lang.Long.TYPE, LongEnc)
    lazy val Long_XOR_Long = LongClass.info.member(nme.XOR).requiredSymbol(
      x => (x is Method) && (x.info.firstParamTypes.head isRef defn.LongClass)
    )
    lazy val Long_LSR_Int = LongClass.info.member(nme.LSR).requiredSymbol(
      x => (x is Method) && (x.info.firstParamTypes.head isRef defn.IntClass)
    )
  lazy val FloatClass = valueClassSymbol("scala.Float", BoxedFloatClass, java.lang.Float.TYPE, FloatEnc)
  lazy val DoubleClass = valueClassSymbol("scala.Double", BoxedDoubleClass, java.lang.Double.TYPE, DoubleEnc)

  lazy val BoxedUnitClass = ctx.requiredClass("scala.runtime.BoxedUnit")

    lazy val BoxedUnit_UNIT = BoxedUnitClass.linkedClass.requiredValue("UNIT")

  lazy val BoxedBooleanClass = ctx.requiredClass("java.lang.Boolean")
  lazy val BoxedByteClass = ctx.requiredClass("java.lang.Byte")
  lazy val BoxedShortClass = ctx.requiredClass("java.lang.Short")
  lazy val BoxedCharClass = ctx.requiredClass("java.lang.Character")
  lazy val BoxedIntClass = ctx.requiredClass("java.lang.Integer")
  lazy val BoxedLongClass = ctx.requiredClass("java.lang.Long")
  lazy val BoxedFloatClass = ctx.requiredClass("java.lang.Float")
  lazy val BoxedDoubleClass = ctx.requiredClass("java.lang.Double")

  lazy val ByNameParamClass2x     = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, AnyType)
  lazy val EqualsPatternClass     = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, AnyType)

  lazy val RepeatedParamClass     = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, SeqType)

  // fundamental classes
  lazy val StringClass                  = ctx.requiredClass("java.lang.String")
  lazy val StringModule                 = StringClass.moduleClass

    lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, methOfAny(StringType), Final)
    lazy val String_valueOf_Object = StringModule.info.member(nme.valueOf).suchThat(_.info.firstParamTypes match {
      case List(pt) => pt isRef ObjectClass
      case _ => false
    }).symbol

  // in scalac modified to have Any as parrent

  lazy val SerializableClass         = ctx.requiredClass("scala.Serializable")
  lazy val JavaCloneableClass        = ctx.requiredClass("java.lang.Cloneable")
  lazy val StringBuilderClass        = ctx.requiredClass("scala.collection.mutable.StringBuilder")
  lazy val NullPointerExceptionClass = ctx.requiredClass(jnme.NPException)
  lazy val MatchErrorClass           = ctx.requiredClass("scala.MatchError")
  lazy val MatchErrorType            = MatchErrorClass.typeRef

  lazy val StringAddClass               = ctx.requiredClass("scala.runtime.StringAdd")

    lazy val StringAdd_+ = StringAddClass.requiredMethod(nme.raw.PLUS)

  lazy val PairClass                    = ctx.requiredClass("dotty.Pair")
  lazy val PartialFunctionClass         = ctx.requiredClass("scala.PartialFunction")
  lazy val AbstractPartialFunctionClass = ctx.requiredClass("scala.runtime.AbstractPartialFunction")
  lazy val SymbolClass                  = ctx.requiredClass("scala.Symbol")
  lazy val ClassClass                   = ctx.requiredClass("java.lang.Class")
  lazy val DynamicClass                 = ctx.requiredClass("scala.Dynamic")
  lazy val OptionClass                  = ctx.requiredClass("scala.Option")
  lazy val BoxedNumberClass             = ctx.requiredClass("java.lang.Number")
  lazy val ThrowableClass               = ctx.requiredClass("java.lang.Throwable")
  lazy val ClassCastExceptionClass      = ctx.requiredClass("java.lang.ClassCastException")
  lazy val JavaSerializableClass        = ctx.requiredClass("java.lang.Serializable")
  lazy val ComparableClass              = ctx.requiredClass("java.lang.Comparable")
  lazy val ProductClass                 = ctx.requiredClass("scala.Product")
    lazy val Product_canEqual = ProductClass.requiredMethod(nme.canEqual_)
    lazy val Product_productArity = ProductClass.requiredMethod(nme.productArity)
  lazy val LanguageModuleClass          = ctx.requiredModule("dotty.language").moduleClass.asClass

  // Annotation base classes
  lazy val AnnotationClass              = ctx.requiredClass("scala.annotation.Annotation")
  lazy val ClassfileAnnotationClass     = ctx.requiredClass("scala.annotation.ClassfileAnnotation")
  lazy val StaticAnnotationClass        = ctx.requiredClass("scala.annotation.StaticAnnotation")
  lazy val TailrecAnnotationClass       = ctx.requiredClass("scala.annotation.tailrec")
  lazy val RemoteAnnot                   = ctx.requiredClass("scala.remote")
  lazy val SerialVersionUIDAnnot         = ctx.requiredClass("scala.SerialVersionUID")
  lazy val TransientAnnot                = ctx.requiredClass("scala.transient")
  lazy val NativeAnnot                   = ctx.requiredClass("scala.native")
  lazy val ScalaStrictFPAnnot            = ctx.requiredClass("scala.annotation.strictfp")

  // Annotation classes
  lazy val AliasAnnot = ctx.requiredClass("dotty.annotation.internal.Alias")
  lazy val ChildAnnot = ctx.requiredClass("dotty.annotation.internal.Child")
  lazy val RepeatedAnnot = ctx.requiredClass("dotty.annotation.internal.Repeated")
  lazy val InvariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.InvariantBetween")
  lazy val CovariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.CovariantBetween")
  lazy val ContravariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.ContravariantBetween")
  lazy val ScalaSignatureAnnot = ctx.requiredClass("scala.reflect.ScalaSignature")
  lazy val ScalaLongSignatureAnnot = ctx.requiredClass("scala.reflect.ScalaLongSignature")
  lazy val DeprecatedAnnot = ctx.requiredClass("scala.deprecated")
  lazy val MigrationAnnot = ctx.requiredClass("scala.annotation.migration")
  lazy val AnnotationDefaultAnnot = ctx.requiredClass("dotty.annotation.internal.AnnotationDefault")
  lazy val ThrowsAnnot = ctx.requiredClass("scala.throws")
  lazy val UncheckedAnnot = ctx.requiredClass("scala.unchecked")
  lazy val UncheckedStableAnnot = ctx.requiredClass("scala.annotation.unchecked.uncheckedStable")
  lazy val UncheckedVarianceAnnot = ctx.requiredClass("scala.annotation.unchecked.uncheckedVariance")
  lazy val VolatileAnnot = ctx.requiredClass("scala.volatile")

  // convenient one-parameter method types
  def methOfAny(tp: Type) = MethodType(List(AnyType), tp)
  def methOfAnyVal(tp: Type) = MethodType(List(AnyValType), tp)
  def methOfAnyRef(tp: Type) = MethodType(List(ObjectType), tp)

  // Derived types
  def AnyType: Type = AnyClass.typeRef
  def AnyValType: Type = AnyValClass.typeRef
  def ObjectType: Type = ObjectClass.typeRef
  def AnyRefType: Type = AnyRefAlias.typeRef
  def NotNullType: Type = NotNullClass.typeRef
  def NothingType: Type = NothingClass.typeRef
  def NullType: Type = NullClass.typeRef
  def SeqType: Type = SeqClass.typeRef

  def UnitType: Type = UnitClass.typeRef
  def BooleanType: Type = BooleanClass.typeRef
  def ByteType: Type = ByteClass.typeRef
  def ShortType: Type = ShortClass.typeRef
  def CharType: Type = CharClass.typeRef
  def IntType: Type = IntClass.typeRef
  def LongType: Type = LongClass.typeRef
  def FloatType: Type = FloatClass.typeRef
  def DoubleType: Type = DoubleClass.typeRef
  def PairType: Type = PairClass.typeRef
  def StringType: Type = StringClass.typeRef
  def RepeatedParamType = RepeatedParamClass.typeRef
  def ThrowableType = ThrowableClass.typeRef
  def OptionType = OptionClass.typeRef
  def VolatileAnnotType = VolatileAnnot.typeRef

  def ClassType(arg: Type)(implicit ctx: Context) = {
    val ctype = ClassClass.typeRef
    if (ctx.phase.erasedTypes) ctype else ctype.appliedTo(arg)
  }

  /** The enumeration type, goven a value of the enumeration */
  def EnumType(sym: Symbol)(implicit ctx: Context) =
    // given (in java): "class A { enum E { VAL1 } }"
    //  - sym: the symbol of the actual enumeration value (VAL1)
    //  - .owner: the ModuleClassSymbol of the enumeration (object E)
    //  - .linkedClass: the ClassSymbol of the enumeration (class E)
    sym.owner.linkedClass.typeRef

  object FunctionType {
    def apply(args: List[Type], resultType: Type)(implicit ctx: Context) =
      FunctionClass(args.length).typeRef.appliedTo(args ::: resultType :: Nil)
    def unapply(ft: Type)(implicit ctx: Context)/*: Option[(List[Type], Type)]*/ = {
      // -language:keepUnions difference: unapply needs result type because inferred type
      // is Some[(List[Type], Type)] | None, which is not a legal unapply type.
      val tsym = ft.typeSymbol
      lazy val targs = ft.argInfos
      if ((FunctionClasses contains tsym) &&
          (targs.length - 1 <= MaxFunctionArity) &&
          (FunctionClass(targs.length - 1) == tsym)) Some(targs.init, targs.last)
      else None
    }
  }

  object ArrayType {
    def apply(elem: Type)(implicit ctx: Context) =
      if (ctx.erasedTypes) JavaArrayType(elem)
      else ArrayClass.typeRef.appliedTo(elem :: Nil)
    def unapply(tp: Type)(implicit ctx: Context) = tp.dealias match {
      case at: RefinedType if (at isRef ArrayClass) && at.argInfos.length == 1 => Some(at.argInfos.head)
      case _ => None
    }
  }

  object MultiArrayType {
    def apply(elem: Type, ndims: Int)(implicit ctx: Context): Type =
      if (ndims == 0) elem else ArrayType(apply(elem, ndims - 1))
    def unapply(tp: Type)(implicit ctx: Context): Option[(Type, Int)] = tp match {
      case ArrayType(elemtp) =>
        elemtp match {
          case MultiArrayType(finalElemTp, n) => Some(finalElemTp, n + 1)
          case _ => Some(elemtp, 1)
        }
      case _ =>
        None
    }
  }

  // ----- Symbol sets ---------------------------------------------------

  lazy val AbstractFunctionClass = mkArityArray("scala.runtime.AbstractFunction", MaxFunctionArity, 0)
  lazy val FunctionClass = mkArityArray("scala.Function", MaxFunctionArity, 0)
    lazy val Function0_apply = FunctionClass(0).requiredMethod(nme.apply)

  lazy val TupleClass = mkArityArray("scala.Tuple", MaxTupleArity, 2)
  lazy val ProductNClass = mkArityArray("scala.Product", MaxTupleArity, 0)

  lazy val FunctionClasses: Set[Symbol] = FunctionClass.toSet
  lazy val TupleClasses: Set[Symbol] = TupleClass.toSet
  lazy val ProductClasses: Set[Symbol] = ProductNClass.toSet

  /** `Modules whose members are in the default namespace and their module classes */
  lazy val UnqualifiedOwners = RootImports.toSet ++ RootImports.map(_.moduleClass)

  lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)

  lazy val isPolymorphicAfterErasure = Set[Symbol](Any_isInstanceOf, Any_asInstanceOf, newRefArrayMethod)

  lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)

  lazy val overriddenBySynthetic = Set[Symbol](Any_equals, Any_hashCode, Any_toString, Product_canEqual)
  def isTupleType(tp: Type)(implicit ctx: Context) = {
    val arity = tp.dealias.argInfos.length
    arity <= MaxTupleArity && (tp isRef TupleClass(arity))
  }

  def tupleType(elems: List[Type]) = {
    TupleClass(elems.size).typeRef.appliedTo(elems)
  }

  def isProductSubType(tp: Type)(implicit ctx: Context) =
    (tp derivesFrom ProductClass) && tp.baseClasses.exists(ProductClasses contains _)

  def isFunctionType(tp: Type)(implicit ctx: Context) = {
    val arity = functionArity(tp)
    0 <= arity && arity <= MaxFunctionArity && (tp isRef FunctionClass(arity))
  }

  def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1

  // ----- LambdaXYZ traits ------------------------------------------

  private var myLambdaTraits: Set[Symbol] = Set()

  /** The set of HigherKindedXYZ traits encountered so far */
  def lambdaTraits: Set[Symbol] = myLambdaTraits

  private var lambdaTraitForVariances = mutable.Map[List[Int], ClassSymbol]()

  /** The HigherKinded trait corresponding to symbols `boundSyms` (which are assumed
   *  to be the type parameters of a higher-kided type). This is a class symbol that
   *  would be generated by the following schema.
   *
   *      class LambdaXYZ extends Object with P1 with ... with Pn {
   *        type v_1 $hk$Arg0; ...; type v_N $hk$ArgN;
   *        type Apply
   *      }
   *
   *  Here:
   *
   *   - v_i are the variances of the bound symbols (i.e. +, -, or empty).
   *   - XYZ is a string of length N with one letter for each variant of a bound symbol,
   *     using `P` (positive variance), `N` (negative variance), `I` (invariant).
   *   - for each positive or negative variance v_i there is a parent trait Pj which
   *     is the same as LambdaXYZ except that it has `I` in i-th position.
   */
  def lambdaTrait(vcs: List[Int]): ClassSymbol = {
    assert(vcs.nonEmpty)

    def varianceFlags(v: Int) = v match {
      case -1 => Contravariant
      case  0 => EmptyFlags
      case  1 => Covariant
    }

    val completer = new LazyType  {
      def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
        val cls = denot.asClass.classSymbol
        val paramDecls = newScope
        for (i <- 0 until vcs.length)
          newTypeParam(cls, tpnme.lambdaArgName(i), varianceFlags(vcs(i)), paramDecls)
        newTypeField(cls, tpnme.Apply, Covariant, paramDecls)
        val parentTraitRefs =
          for (i <- 0 until vcs.length if vcs(i) != 0)
          yield lambdaTrait(vcs.updated(i, 0)).typeRef
        denot.info = ClassInfo(
            ScalaPackageClass.thisType, cls, ObjectClass.typeRef :: parentTraitRefs.toList, paramDecls)
      }
    }

    val traitName = tpnme.lambdaTraitName(vcs)

    def createTrait = {
      val cls = newClassSymbol(
        ScalaPackageClass,
        traitName,
        PureInterfaceCreationFlags | Synthetic,
        completer)
      myLambdaTraits += cls
      cls
    }

    lambdaTraitForVariances.getOrElseUpdate(vcs, createTrait)
  }

  // ----- primitive value class machinery ------------------------------------------

  lazy val ScalaNumericValueClasses: collection.Set[Symbol] =  Set(
    ByteClass,
    ShortClass,
    CharClass,
    IntClass,
    LongClass,
    FloatClass,
    DoubleClass)

  lazy val ScalaValueClasses: collection.Set[Symbol] = ScalaNumericValueClasses + UnitClass + BooleanClass

  lazy val ScalaBoxedClasses = ScalaValueClasses map boxedClass

  private[this] val _boxedClass = mutable.Map[Symbol, Symbol]()
  private[this] val _unboxedClass = mutable.Map[Symbol, Symbol]()

  private[this] val _javaTypeToValueClass = mutable.Map[Class[_], Symbol]()
  private[this] val _valueClassToJavaType = mutable.Map[Symbol, Class[_]]()
  private[this] val _valueClassEnc = mutable.Map[Symbol, Int]()

  val boxedClass: collection.Map[Symbol, Symbol] = _boxedClass
  val unboxedClass: collection.Map[Symbol, Symbol] = _boxedClass
  val javaTypeToValueClass: collection.Map[Class[_], Symbol] = _javaTypeToValueClass
  val valueClassToJavaType: collection.Map[Symbol, Class[_]] = _valueClassToJavaType
  val valueClassEnc: collection.Map[Symbol, Int] = _valueClassEnc

  private def valueClassSymbol(name: String, boxed: ClassSymbol, jtype: Class[_], enc: Int): ClassSymbol = {
    val vcls = ctx.requiredClass(name)
    _unboxedClass(boxed) = vcls
    _boxedClass(vcls) = boxed
    _javaTypeToValueClass(jtype) = vcls
    _valueClassToJavaType(vcls) = jtype
    _valueClassEnc(vcls) = enc
    vcls
  }

  /** The classes for which a Ref type exists. */
  lazy val refClasses: collection.Set[Symbol] = ScalaNumericValueClasses + BooleanClass + ObjectClass

  lazy val refClass: Map[Symbol, Symbol] =
    refClasses.map(rc => rc -> ctx.requiredClass(s"scala.runtime.${rc.name}Ref")).toMap

  lazy val volatileRefClass: Map[Symbol, Symbol] =
    refClasses.map(rc => rc -> ctx.requiredClass(s"scala.runtime.Volatile${rc.name}Ref")).toMap

  def wrapArrayMethodName(elemtp: Type): TermName = {
    val cls = elemtp.classSymbol
    if (cls.isPrimitiveValueClass) nme.wrapXArray(cls.name)
    else if (cls.derivesFrom(ObjectClass) && !cls.isPhantomClass) nme.wrapRefArray
    else nme.genericWrapArray
  }

  val ByteEnc = 2
  val ShortEnc = ByteEnc * 3
  val CharEnc = 5
  val IntEnc = ShortEnc * CharEnc
  val LongEnc = IntEnc * 7
  val FloatEnc = LongEnc * 11
  val DoubleEnc = FloatEnc * 13
  val BooleanEnc = 17
  val UnitEnc = 19

  def isValueSubClass(cls1: Symbol, cls2: Symbol)(implicit ctx: Context) =
    valueClassEnc(cls2) % valueClassEnc(cls1) == 0

  // ----- Initialization ---------------------------------------------------

  /** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
  lazy val syntheticCoreClasses = List(
    AnyClass,
    AnyRefAlias,
    RepeatedParamClass,
    ByNameParamClass2x,
    AnyValClass,
    NullClass,
    NothingClass,
    SingletonClass,
    EqualsPatternClass,
    EmptyPackageVal)

    /** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
    lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+)

  private[this] var _isInitialized = false
  def isInitialized = _isInitialized

  def init(implicit ctx: Context) = {
    this.ctx = ctx
    if (!_isInitialized) {
      // force initialization of every symbol that is synthesized or hijacked by the compiler
      val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses
      _isInitialized = true
    }
  }
}

{'fraction_non_alphanumeric': 0.10285262257236491, 'fraction_numerical': 0.00200184040165959, 'mean_word_length': 3.9842291599613775, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7547788', 'n_tokens_mistral': 18891, 'n_tokens_neox': 18680, 'n_words': 4732}