package dotty.tools.dotc.core import language.implicitConversions object Flags { /** A FlagSet represents a set of flags. Flags are encoded as follows: * The first two bits indicate whether a flagset applies to terms, * to types, or to both. Bits 2..63 are available for properties * and can be doubly used for terms and types. * Combining two FlagSets with `|` will give a FlagSet * that has the intersection of the applicability to terms/types * of the two flag sets. It is checked that the intersection is not empty. */ case class FlagSet(val bits: Long) extends AnyVal { /** The union of this flag set and the given flag set */ def | (that: FlagSet): FlagSet = if (bits == 0) that else if (that.bits == 0) this else { val tbits = bits & that.bits & KINDFLAGS assert(tbits != 0, s"illegal flagset combination: $this and $that") FlagSet(tbits | ((this.bits | that.bits) & ~KINDFLAGS)) } /** The intersection of this flag set and the given flag set */ def & (that: FlagSet) = FlagSet(bits & that.bits) /** The intersection of this flag set with the complement of the given flag set */ def &~ (that: FlagSet) = { val tbits = bits & KINDFLAGS if ((tbits & that.bits) == 0) this else FlagSet(tbits | ((this.bits & ~that.bits) & ~KINDFLAGS)) } /** Does this flag set have a non-empty intersection with the given flag set? * This means that both the kind flags and the carrier bits have non-empty intersection. */ def is(flags: FlagSet): Boolean = { val fs = bits & flags.bits (fs & KINDFLAGS) != 0 && (fs & ~KINDFLAGS) != 0 } /** Does this flag set have a non-empty intersection with the given flag set, * and at the same time contain none of the flags in the `butNot` set? */ def is(flags: FlagSet, butNot: FlagSet): Boolean = is(flags) && !is(butNot) /** Does this flag set have all of the flags in given flag conjunction? * Pre: The intersection of the typeflags of both sets must be non-empty. */ def is(flags: FlagConjunction): Boolean = { val fs = bits & flags.bits (fs & KINDFLAGS) != 0 && (fs >>> TYPESHIFT) == (flags.bits >>> TYPESHIFT) } /** Does this flag set have all of the flags in given flag conjunction? * and at the same time contain none of the flags in the `butNot` set? * Pre: The intersection of the typeflags of both sets must be non-empty. */ def is(flags: FlagConjunction, butNot: FlagSet): Boolean = is(flags) && !is(butNot) def isEmpty = (bits & ~KINDFLAGS) == 0 /** Is this flag set a subset of that one? */ def <= (that: FlagSet) = (bits & that.bits) == bits /** Does this flag set apply to terms? */ def isTermFlags = (bits & TERMS) != 0 /** Does this flag set apply to terms? */ def isTypeFlags = (bits & TYPES) != 0 /** This flag set with all flags transposed to be type flags */ def toTypeFlags = if (bits == 0) this else FlagSet(bits & ~KINDFLAGS | TYPES) /** This flag set with all flags transposed to be term flags */ def toTermFlags = if (bits == 0) this else FlagSet(bits & ~KINDFLAGS | TERMS) /** This flag set with all flags transposed to be common flags */ def toCommonFlags = if (bits == 0) this else FlagSet(bits | KINDFLAGS) /** The number of non-kind flags in this set */ def numFlags: Int = java.lang.Long.bitCount(bits & ~KINDFLAGS) /** The lowest non-kind bit set in this flagset */ def firstBit: Int = java.lang.Long.numberOfTrailingZeros(bits & ~KINDFLAGS) /** The list of non-empty names of flags with given index idx that are set in this FlagSet */ private def flagString(idx: Int): List[String] = if ((bits & (1L << idx)) == 0) Nil else { def halfString(kind: Int) = if ((bits & (1L << kind)) != 0) flagName(idx)(kind) else "" val termFS = halfString(TERMindex) val typeFS = halfString(TYPEindex) val strs = termFS :: (if (termFS == typeFS) Nil else typeFS :: Nil) strs filter (_.nonEmpty) } /** The list of non-empty names of flags that are set in this FlagSet */ def flagStrings: Seq[String] = { val rawStrings = (2 to MaxFlag).flatMap(flagString) if (this is Local) rawStrings.filter(_ != "").map { case "private" => "private[this]" case "protected" => "protected[this]" case str => str } else rawStrings } /** The string representation of this flag set */ override def toString = flagStrings.mkString(" ") } /** A class representing flag sets that should be tested * conjunctively. I.e. for a flag conjunction `fc`, * `x is fc` tests whether `x` contains all flags in `fc`. */ case class FlagConjunction(bits: Long) { override def toString = FlagSet(bits).toString } private final val TYPESHIFT = 2 private final val TERMindex = 0 private final val TYPEindex = 1 private final val TERMS = 1 << TERMindex private final val TYPES = 1 << TYPEindex private final val KINDFLAGS = TERMS | TYPES private final val FirstFlag = 2 private final val FirstNotPickledFlag = 48 private final val MaxFlag = 63 private val flagName = Array.fill(64, 2)("") private def isDefinedAsFlag(idx: Int) = flagName(idx) exists (_.nonEmpty) /** The flag set containing all defined flags of either kind whose bits * lie in the given range */ private def flagRange(start: Int, end: Int) = FlagSet((KINDFLAGS.toLong /: (start until end)) ((bits, idx) => if (isDefinedAsFlag(idx)) bits | (1L << idx) else bits)) /** The flag with given index between 2 and 63 which applies to terms. * Installs given name as the name of the flag. */ private def termFlag(index: Int, name: String): FlagSet = { flagName(index)(TERMindex) = name FlagSet(TERMS | (1L << index)) } /** The flag with given index between 2 and 63 which applies to types. * Installs given name as the name of the flag. */ private def typeFlag(index: Int, name: String): FlagSet = { flagName(index)(TYPEindex) = name FlagSet(TYPES | (1L << index)) } /** The flag with given index between 2 and 63 which applies to both terms and types * Installs given name as the name of the flag. */ private def commonFlag(index: Int, name: String): FlagSet = { flagName(index)(TERMindex) = name flagName(index)(TYPEindex) = name FlagSet(TERMS | TYPES | (1L << index)) } /** The union of all flags in given flag set */ def union(flagss: FlagSet*) = (EmptyFlags /: flagss)(_ | _) /** The conjunction of all flags in given flag set */ def allOf(flagss: FlagSet*) = { assert(flagss forall (_.numFlags == 1), "Flags.allOf doesn't support flag " + flagss.find(_.numFlags != 1)) FlagConjunction(union(flagss: _*).bits) } def commonFlags(flagss: FlagSet*) = union(flagss.map(_.toCommonFlags): _*) /** The empty flag set */ final val EmptyFlags = FlagSet(0) /** The undefined flag set */ final val UndefinedFlags = FlagSet(~KINDFLAGS) // Available flags: /** Labeled with `private` modifier */ final val Private = commonFlag(2, "private") final val PrivateTerm = Private.toTermFlags final val PrivateType = Private.toTypeFlags /** Labeled with `protected` modifier */ final val Protected = commonFlag(3, "protected") /** Labeled with `override` modifier */ final val Override = commonFlag(4, "override") /** A declared, but not defined member */ final val Deferred = commonFlag(5, "") final val DeferredTerm = Deferred.toTermFlags final val DeferredType = Deferred.toTypeFlags /** Labeled with `final` modifier */ final val Final = commonFlag(6, "final") /** A method symbol. */ final val MethodOrHKCommon = commonFlag(7, "") final val Method = MethodOrHKCommon.toTermFlags final val HigherKinded = MethodOrHKCommon.toTypeFlags /** A (term or type) parameter to a class or method */ final val Param = commonFlag(8, "") final val TermParam = Param.toTermFlags final val TypeParam = Param.toTypeFlags /** Labeled with `implicit` modifier (implicit value) */ final val ImplicitCommon = commonFlag(9, "implicit") final val Implicit = ImplicitCommon.toTermFlags /** Labeled with `lazy` (a lazy val). */ final val Lazy = termFlag(10, "lazy") /** A trait */ final val Trait = typeFlag(10, "") final val LazyOrTrait = Lazy.toCommonFlags /** A value or variable accessor (getter or setter) */ final val Accessor = termFlag(11, "") /** Labeled with `sealed` modifier (sealed class) */ final val Sealed = typeFlag(11, "sealed") final val AccessorOrSealed = Accessor.toCommonFlags /** A mutable var */ final val Mutable = termFlag(12, "mutable") /** Symbol is local to current class (i.e. private[this] or protected[this] * pre: Private or Protected are also set */ final val Local = commonFlag(13, "") /** A field generated for a primary constructor parameter (no matter if it's a 'val' or not), * or an accessor of such a field. */ final val ParamAccessor = commonFlag(14, "") final val TermParamAccessor = ParamAccessor.toTermFlags final val TypeParamAccessor = ParamAccessor.toTypeFlags /** A value or class implementing a module */ final val Module = commonFlag(15, "module") final val ModuleVal = Module.toTermFlags final val ModuleClass = Module.toTypeFlags /** A value or class representing a package */ final val Package = commonFlag(16, "") final val PackageVal = Package.toTermFlags final val PackageClass = Package.toTypeFlags /** A case class or its companion object */ final val Case = commonFlag(17, "case") final val CaseClass = Case.toTypeFlags final val CaseVal = Case.toTermFlags /** A compiler-generated symbol, which is visible for type-checking * (compare with artifact) */ final val Synthetic = commonFlag(18, "") /** A covariant type variable / an outer accessor */ final val CovariantOrOuter = commonFlag(20, "") final val Covariant = typeFlag(20, "") final val OuterAccessor = termFlag(20, "") /** A contravariant type variable / a label method */ final val ContravariantOrLabel = commonFlag(21, "") final val Contravariant = typeFlag(21, "") final val Label = termFlag(21, "