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(_ != "<local>").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, "<deferred>")
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, "<method>")
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, "<param>")
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, "<trait>")
final val LazyOrTrait = Lazy.toCommonFlags
/** A value or variable accessor (getter or setter) */
final val Accessor = termFlag(11, "<accessor>")
/** 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, "<local>")
/** 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, "<paramaccessor>")
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, "<package>")
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, "<synthetic>")
/** A covariant type variable / an outer accessor */
final val CovariantOrOuter = commonFlag(20, "")
final val Covariant = typeFlag(20, "<covariant>")
final val OuterAccessor = termFlag(20, "<outer accessor>")
/** A contravariant type variable / a label method */
final val ContravariantOrLabel = commonFlag(21, "")
final val Contravariant = typeFlag(21, "<contravariant>")
final val Label = termFlag(21, "<label>")
/** A trait that has only abstract methods as members
* and therefore can be represented by a Java interface.
* Warning: flag is set during regular typer pass, should be tested only after typer.
*/
final val PureInterface = typeFlag(22, "interface")
/** Labeled with of abstract & override */
final val AbsOverride = termFlag(22, "abstract override")
/** Labeled with `abstract` modifier (an abstract class)
* Note: You should never see Abstract on any symbol except a class.
* Note: the flag counts as common, because it can be combined with OVERRIDE in a term.
*/
final val Abstract = commonFlag(23, "abstract")
/** Lazy val or method is known or assumed to be stable and realizable */
final val Stable = termFlag(24, "<stable>")
/** A case parameter accessor */
final val CaseAccessor = termFlag(25, "<caseaccessor>")
/** A binding for a type parameter of a base class or trait.
*/
final val BaseTypeArg = typeFlag(25, "<basetypearg>")
final val CaseAccessorOrBaseTypeArg = CaseAccessor.toCommonFlags
/** A super accessor */
final val Scala2SuperAccessor = termFlag(26, "<superaccessor>")
/** An unpickled Scala 2.x class */
final val Scala2x = typeFlag(26, "<scala-2.x>")
final val SuperAccessorOrScala2x = Scala2x.toCommonFlags
/** A method that has default params */
final val DefaultParameterized = termFlag(27, "<defaultparam>")
/** A type that is defined by a type bind */
final val BindDefinedType = typeFlag(27, "<bind-defined>")
/** Symbol is inlined */
final val Inline = commonFlag(29, "inline")
/** Symbol is defined by a Java class */
final val JavaDefined = commonFlag(30, "<java>")
/** Symbol is implemented as a Java static */
final val JavaStatic = commonFlag(31, "<static>")
final val JavaStaticTerm = JavaStatic.toTermFlags
final val JavaStaticType = JavaStatic.toTypeFlags
/** Trait does not have fields or initialization code.
* Warning: flag is set during regular typer pass, should be tested only after typer.
*/
final val NoInits = typeFlag(32, "<noInits>")
/** Variable is accessed from nested function. */
final val Captured = termFlag(32, "<captured>")
/** Symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode */
final val Artifact = commonFlag(33, "<artifact>")
/** A bridge method. Set by Erasure */
final val Bridge = termFlag(34, "<bridge>")
/** All class attributes are fully defined */
final val FullyCompleted = typeFlag(34, "<fully-completed>")
/** Symbol is a Java varargs bridge */ // (needed?)
final val VBridge = termFlag(35, "<vbridge>") // TODO remove
/** Symbol is a method which should be marked ACC_SYNCHRONIZED */
final val Synchronized = termFlag(36, "<synchronized>")
/** Symbol is a Java-style varargs method */
final val JavaVarargs = termFlag(37, "<varargs>")
/** Symbol is a Java default method */
final val DefaultMethod = termFlag(38, "<defaultmethod>")
/** Symbol is a Java enum */
final val Enum = commonFlag(40, "<enum>")
// Flags following this one are not pickled
/** Symbol always defines a fresh named type */
final val Fresh = commonFlag(45, "<fresh>")
/** Symbol is defined in a super call */
final val InSuperCall = commonFlag(46, "<in supercall>")
/** Denotation is in train of being loaded and completed, used to catch cyclic dependencies */
final val Touched = commonFlag(48, "<touched>")
/** Class is not allowed to accept new members because fingerprint of subclass has been taken */
final val Frozen = commonFlag(49, "<frozen>")
/** An error symbol */
final val Erroneous = commonFlag(50, "<is-error>")
/** Class has been lifted out to package level, local value has been lifted out to class level */
final val Lifted = commonFlag(51, "<lifted>")
/** Term member has been mixed in */
final val MixedIn = commonFlag(52, "<mixedin>")
/** Symbol is a generated specialized member */
final val Specialized = commonFlag(53, "<specialized>")
/** Symbol is a self name */
final val SelfName = termFlag(54, "<selfname>")
/** Symbol is an implementation class of a Scala2 trait */
final val ImplClass = typeFlag(54, "<implclass>")
final val SelfNameOrImplClass = SelfName.toCommonFlags
/** An existentially bound symbol (Scala 2.x only) */
final val Scala2ExistentialCommon = commonFlag(55, "<existential>")
final val Scala2Existential = Scala2ExistentialCommon.toTypeFlags
/** A module variable (Scala 2.x only) */
final val Scala2ModuleVar = termFlag(57, "<modulevar>")
/** A definition that's initialized before the super call (Scala 2.x only) */
final val Scala2PreSuper = termFlag(58, "<presuper>")
/** A macro (Scala 2.x only) */
final val Macro = commonFlag(59, "<macro>")
/** A method that is known to have inherited default parameters */
final val InheritedDefaultParams = termFlag(60, "<inherited-default-param>")
/** Translation of Scala2's EXPANDEDNAME flag. This flag is never stored in
* symbols, is only used locally when reading the flags of a Scala2 symbol.
* It's therefore safe to share the code with `InheritedDefaultParams` because
* the latter is never present in Scala2 unpickle info.
*/
final val Scala2ExpandedName = InheritedDefaultParams.toCommonFlags
/** A method that is known to have no default parameters */
final val NoDefaultParams = termFlag(61, "<no-default-param>")
/** A denotation that is valid in all run-ids */
final val Permanent = commonFlag(62, "<permanent>")
// --------- Combined Flag Sets and Conjunctions ----------------------
/** Flags representing source modifiers */
final val SourceModifierFlags =
commonFlags(Private, Protected, Abstract, Final, Inline,
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic)
/** Flags representing modifiers that can appear in trees */
final val ModifierFlags =
SourceModifierFlags | Module | Param | Synthetic | Package | Local |
commonFlags(Mutable)
// | Trait is subsumed by commonFlags(Lazy) from SourceModifierFlags
assert(ModifierFlags.isTermFlags && ModifierFlags.isTypeFlags)
/** Flags representing access rights */
final val AccessFlags = Private | Protected | Local
/** Flags guaranteed to be set upon symbol creation */
final val FromStartFlags =
Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor |
Scala2ExistentialCommon | Mutable.toCommonFlags | InSuperCall | Touched | JavaStatic |
CovariantOrOuter | ContravariantOrLabel | CaseAccessorOrBaseTypeArg |
Fresh | Frozen | Erroneous | ImplicitCommon | Permanent | Synthetic |
SuperAccessorOrScala2x | Inline
/** Flags guaranteed to be set upon symbol creation, or, if symbol is a top-level
* class or object, when the class file defining the symbol is loaded (which
* is generally before the symbol is completed
*/
final val AfterLoadFlags =
FromStartFlags | AccessFlags | Final | AccessorOrSealed | LazyOrTrait | SelfNameOrImplClass
assert(FromStartFlags.isTermFlags && FromStartFlags.isTypeFlags)
// TODO: Should check that FromStartFlags do not change in completion
assert(AfterLoadFlags.isTermFlags && AfterLoadFlags.isTypeFlags)
/** A value that's unstable unless complemented with a Stable flag */
final val UnstableValue = Mutable | Method
/** Flags that express the variance of a type parameter. */
final val VarianceFlags = Covariant | Contravariant
/** Flags that are passed from a type parameter of a class to a refinement symbol
* that sets the type parameter */
final val RetainedTypeArgFlags = VarianceFlags | Protected | Local
/** Modules always have these flags set */
final val ModuleCreationFlags = ModuleVal | Lazy | Final | Stable
/** Module classes always have these flags set */
final val ModuleClassCreationFlags = ModuleClass | Final
/** Accessors always have these flags set */
final val AccessorCreationFlags = Method | Accessor
/** Pure interfaces always have these flags */
final val PureInterfaceCreationFlags = Trait | NoInits | PureInterface
final val NoInitsInterface = NoInits | PureInterface
/** The flags of the self symbol */
final val SelfSymFlags = Private | Local | Deferred
/** The flags of a class type parameter */
final def ClassTypeParamCreationFlags = TypeParam | Deferred | Protected | Local
/** Flags that can apply to both a module val and a module class, except those that
* are added at creation anyway
*/
final val RetainedModuleValAndClassFlags: FlagSet =
AccessFlags | Package | Case |
Synthetic | JavaDefined | JavaStatic | Artifact |
Erroneous | Lifted | MixedIn | Specialized
/** Flags that can apply to a module val */
final val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags |
Override | Final | Method | Implicit | Lazy |
Accessor | AbsOverride | Stable | Captured | Synchronized
/** Flags that can apply to a module class */
final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags |
InSuperCall | ImplClass
/** Packages and package classes always have these flags set */
final val PackageCreationFlags =
Module | Package | Final | JavaDefined
/** These flags are pickled */
final val PickledFlags = flagRange(FirstFlag, FirstNotPickledFlag)
final val AnyFlags = flagRange(FirstFlag, MaxFlag)
/** An abstract class or a trait */
final val AbstractOrTrait = Abstract | Trait
/** Labeled `private` or `protected[local]` */
final val PrivateOrLocal = Private | Local
/** Either a module or a final class */
final val ModuleOrFinal = ModuleClass | Final
/** Either mutable or lazy */
final val MutableOrLazy = Mutable | Lazy
/** Either method or lazy */
final val MethodOrLazy = Method | Lazy
/** Either method or lazy or deferred */
final val MethodOrLazyOrDeferred = Method | Lazy | Deferred
/** Labeled `private`, `final`, or `inline` */
final val PrivateOrFinalOrInline = Private | Final | Inline
/** A private method */
final val PrivateMethod = allOf(Private, Method)
/** A private accessor */
final val PrivateAccessor = allOf(Private, Accessor)
/** An inline method */
final val InlineMethod = allOf(Inline, Method)
/** An inline parameter */
final val InlineParam = allOf(Inline, Param)
/** A parameter or parameter accessor */
final val ParamOrAccessor = Param | ParamAccessor
/** A lazy or deferred value */
final val LazyOrDeferred = Lazy | Deferred
/** A synthetic or private definition */
final val SyntheticOrPrivate = Synthetic | Private
/** A type parameter or type parameter accessor */
final val TypeParamOrAccessor = TypeParam | TypeParamAccessor
/** A deferred member or a parameter accessor (these don't have right hand sides) */
final val DeferredOrParamAccessor = Deferred | ParamAccessor
/** value that's final or inline */
final val FinalOrInline = Final | Inline
/** If symbol of a type alias has these flags, prefer the alias */
final val AliasPreferred = TypeParam | BaseTypeArg
/** A covariant type parameter instance */
final val LocalCovariant = allOf(Local, Covariant)
/** A contravariant type parameter instance */
final val LocalContravariant = allOf(Local, Contravariant)
/** Has defined or inherited default parameters */
final val HasDefaultParams = DefaultParameterized | InheritedDefaultParams
/** Is valid forever */
final val ValidForever = Package | Permanent | Scala2ExistentialCommon
/** Is a default parameter in Scala 2*/
final val DefaultParameter = allOf(Param, DefaultParameterized)
/** A trait that does not need to be initialized */
final val NoInitsTrait = allOf(Trait, NoInits)
/** A Java interface, potentially with default methods */
final val JavaTrait = allOf(JavaDefined, Trait, NoInits)
/** A Java interface */ // TODO when unpickling, reconstitute from context
final val JavaInterface = allOf(JavaDefined, Trait)
/** A Java companion object */
final val JavaModule = allOf(JavaDefined, Module)
/** A Java companion object */
final val JavaProtected = allOf(JavaDefined, Protected)
/** Labeled private[this] */
final val PrivateLocal = allOf(Private, Local)
/** A private[this] parameter accessor */
final val PrivateLocalParamAccessor = allOf(Private, Local, ParamAccessor)
/** A parameter forwarder */
final val ParamForwarder = allOf(Method, Stable, ParamAccessor)
/** A private[this] parameter */
final val PrivateLocalParam = allOf(Private, Local, Param)
/** A private parameter accessor */
final val PrivateParamAccessor = allOf(Private, ParamAccessor)
/** A local parameter */
final val ParamAndLocal = allOf(Param, Local)
/** Labeled protected[this] */
final val ProtectedLocal = allOf(Protected, Local)
/** Java symbol which is `protected` and `static` */
final val StaticProtected = allOf(JavaDefined, Protected, JavaStatic)
final val AbstractFinal = allOf(Abstract, Final)
final val AbstractSealed = allOf(Abstract, Sealed)
final val SyntheticArtifact = allOf(Synthetic, Artifact)
final val SyntheticModule = allOf(Synthetic, Module)
final val SyntheticTermParam = allOf(Synthetic, TermParam)
final val SyntheticTypeParam = allOf(Synthetic, TypeParam)
final val SyntheticCase = allOf(Synthetic, Case)
final val AbstractAndOverride = allOf(Abstract, Override)
final val Scala2Trait = allOf(Scala2x, Trait)
implicit def conjToFlagSet(conj: FlagConjunction): FlagSet =
FlagSet(conj.bits)
}