summaryrefslogblamecommitdiff
path: root/src/reflect/scala/reflect/api/Symbols.scala
blob: 371e20cdd407ca590b543ac875660801e5cf7ba9 (plain) (tree)
1
2
3
4
5
6


                     

                                                                                                                    
  




































































































































































































                                                                                                                                                                   








































































                                                                                           
 


                                                                                             





                                                                             

                                                                                         
                                                             
                                               



















































































































                                                                                                                              
 

                                                                          



                                                                                                                        
       
                                                     
 

                                                      
                                     
 















                                                                                             


                                                        







                                                                                  




                                                                                              






















                                                                                     



















                                                                                     



                                                                                           


                             
                                                               

                                                       
                          
 

                                                        
       
                               
 
                                                                               


                             






                                                                                                                               







                                            



                                                       



                               







                                                                                      



                                       



                                                                                     

                                                     
                                                      
       
                                      
 



                                                                       
       






                                                          
                                                                             

                                                 

   


                                                                                             







                                                             
                                           
       
                      



                                                  
                                           
       
                      



















                                                                                                                   



                                                

                                                     
 


                                                                                










                                                                                                 


















                                                                          

   


                                                                                             


































                                                                                          







                                                                       

                                                                                                          
       
                                
 










                                                                      


                                                                                          
   
 


                                                                                             



                                                                     






                                                                      


                                                                                  


                                                                                              
                                          
                                                                                    




                                                                                                                     
                                   
 



                                                                

                                        
   
 


                                                                                             









                                                                                           
   
 


                                                                                             



                                                                   
































                                                                                                              




                                                               





                                                                                 




                                                         


                                                                             
                      
 

                                                            


                                                                                                         
   
 


                                                                                             



                                                                         






                                                       


                                                                                             



                                                                         

                                                       
   
 
package scala.reflect
package api

/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines symbols and operations on them.
 *  See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
 *
 *  === Symbols from a compile-time perspective ===
 *
 *  [[http://dcsobral.blogspot.ch/2012/08/json-serialization-with-reflection-in.html To quote Daniel Sobral]],
 *  anything you define in Scala has a symbol. If you give something a name,
 *  then it has a symbol associated with it. If you didn't give it a name, but you could have, then it has a symbol.
 *
 *  Symbols are used by the Scala compiler to establish bindings. When typechecking a Scala program,
 *  the compiler populates [[scala.reflect.api.Trees#RefTrees ref trees]], such as [[scala.reflect.api.Trees#Ident Ident]]
 *  (references to identifiers) and [[scala.reflect.api.Trees#Select Select]] (references to members)
 *  with symbols that represent the declarations being referred to. Populating means setting the `symbol`
 *  field to a non-empty value.
 *
 *  Here's an example of how trees look after the `typer` phase of the Scala compiler (this phase performs the typechecking).
 *  {{{
 *  >cat Test.scala
 *  def foo[T: TypeTag](x: Any) = x.asInstanceOf[T]
 *
 *  >scalac -Xprint:typer -uniqid Test.scala
 *  [[syntax trees at end of typer]]// Scala source: Test.scala
 *  def foo#8339
 *    [T#8340 >: Nothing#4658 <: Any#4657]
 *    (x#9529: Any#4657)
 *    (implicit evidence$1#9530: TypeTag#7861[T#8341])
 *    : T#8340 =
 *  x#9529.asInstanceOf#6023[T#8341];
 *  }}}
 *
 *  Shortly put, we write a small snippet and then compile it with scalac, asking the compiler to dump the trees
 *  after the typer phase, printing unique ids of the symbols assigned to trees (if any).
 *
 *  The resulting printout shows that identifiers have been linked to corresponding definitions.
 *  For example, on the one hand, the `ValDef("x", ...)`, which represents the parameter of the method `foo`,
 *  defines a method symbol with `id=9529`. On the other hand, the `Ident("x")` in the body of the method
 *  got its `symbol` field set to the same symbol, which establishes the binding.
 *
 *  In the light of this discussion, it might come as a surprise that the definition of the type parameter `T`
 *  has a symbol with `id=8340`, whereas references to this type parameter all have a symbol with `id=8341`.
 *  This is the only exception from the general principe outlined above. It happens because the Scala compiler
 *  skolemizes type parameters (creates new symbols very similar to the original ones) before entering scopes
 *  that define these parameters. This is an advanced feature of Scala, and the knowledge of it is needed only
 *  when writing complex macros, but symbols in the macro universe [[scala.reflect.macros.Universe]] have the
 *  `deskolemize` method, which goes back from skolems to the originating type parameters.
 *
 *  === Symbols from a runtime perspective ===
 *
 *  From the point of view of a runtime reflection framework, symbols are akin to [[java.lang.reflect.Member]] from Java
 *  and [[System.Reflection.MemberInfo]] from .NET. But not only they represent members - they also represent
 *  classes, objects and even packages.
 *
 *  Also similarly to the base classes in the reflection facilities of JVM and .NET, Scala symbols have subclasses
 *  that describe particular flavors of definitions. [[scala.reflect.api.Symbols#TermSymbol]] models term definitions
 *  (such as lazy and eager vals, vars and parameters of methods). Its subclasses are [[scala.reflect.api.Symbols#MethodSymbol]]
 *  and [[scala.reflect.api.Symbols#ModuleSymbol]] (representing "modules", which in Scala compiler speak mean "objects").
 *  [[scala.reflect.api.Symbols#TypeSymbol]] along with its subclass [[scala.reflect.api.Symbols#ClassSymbol]]
 *  describes type definitions in Scala (type aliases, type members, type parameters, classes and traits).
 *
 *  Most reflection APIs that return symbols return non-specific [[scala.reflect.api.Symbols#Symbol]], because upon failure
 *  they don't raise exceptions, but rather produce `NoSymbol`, a special singleton, which is a null object for symbols.
 *  Therefore to use such APIs one has to first check whether a callee returned a valid symbol and, if yes, then perform
 *  a cast using one of the `asTerm`, `asMethod`, `asModule`, `asType` or `asClass` methods. This is arguably inconvenient
 *  and might be improved in the future.
 *
 *  Unlike [[scala.reflect.api.Trees trees]] and [[scala.reflect.api.Types types]], symbols should not be created directly.
 *  Instead one should load the symbols from the global symbol table maintained by the compiler.
 *  To get a symbol that corresponds to a top-level class or object, one can use the `staticClass` and `staticModule`
 *  methods of [[scala.reflect.api.Mirror]]. To get a symbol that corresponds to a certain member, there are `members`
 *  and `declarations` methods of [[scala.reflect.api.Types#Type]], which brings the discussion to the next point: type signatures.
 *
 *  Each symbol has a type signature, which describes its type and is available via the `typeSignature` method
 *  on [[scala.reflect.api.Symbols#Symbol]]. Classes have signatures of the [[scala.reflect.api.Types#ClassInfoType]] type,
 *  which knows the list of its members and declarations. Modules per se don't have interesting signatures. To access members
 *  of modules, one first has to obtain a module class (using the `moduleClass` method) and then inspect its signature.
 *  Members have type signatures of their own: method signatures feature information about parameters and result types,
 *  type member signatures store upper and lower bounds and so on.
 *
 *  One thing to know about type signatures is that `typeSignature` method always returns signatures in the most generic
 *  way possible, even if the underlying symbol is obtained from an instantiation of a generic type. For example, signature
 *  of the method `def map[B](f: (A) ⇒ B): List[B]`, which refers to the type parameter `A` of the declaring class `List[A]`,
 *  will always feature `A`, regardless of whether `map` is loaded from the `List[_]` or from `List[Int]`. To get a signature
 *  with type parameters appropriately instantiated, one should use `typeSignatureIn`.
 *
 *  Symbols are at the heart of the reflection API. Along with the type signatures, which are arguably the most important
 *  use of reflection, they provide comprehensive information about the underlying definitions. This includes various
 *  `isXXX` test methods such as `isPublic` or `isFinal`, `params` and `returnType` methods for method symbols,
 *  `baseClasses` for class symbols and so on. Be prepared - some of these methods don't make sense on the ultimate
 *   base class Symbol, so they are declared in subclasses.
 *
 *  === Exploring symbols ===
 *
 *  In this example we'll try to get a hold on a symbol that represents the `map` method of `List`,
 *  and then do something interesting with it.
 *
 *  First of all, to obtain a symbol, one needs to load its enclosing top-level class or module.
 *  There are two ways of doing that. The first one is getting a symbol by its name using a mirror
 *  (refer to [[scala.reflect.api.package the reflection overview]] for information about mirrors).
 *  Another one is getting a type with [[scaa.reflect.api.Types#typeOf]] and using its `typeSymbol` method.
 *  The second approach is preferable, because it's typesafe, but sometimes it's unavailable.
 *
 *  {{{
 *  scala> import scala.reflect.runtime.universe._
 *  import scala.reflect.runtime.universe._
 *
 *  scala> val cm = runtimeMirror(getClass.getClassLoader)
 *  cm: reflect.runtime.universe.Mirror = JavaMirror with ...
 *
 *  scala> val list = cm.staticClass("scala.List")
 *  list: reflect.runtime.universe.ClassSymbol = class List
 *
 *  scala> val list = typeOf[List[_]].typeSymbol
 *  list: reflect.runtime.universe.Symbol = class List
 *  }}}
 *
 *  Now when the enclosing class is obtained, there's a straight path to getting its member
 *  using `typeSignature` and `member` methods discussed above:
 *
 *  {{{
 *  scala> val map = list.typeSignature.member("map": TermName).asMethod
 *  map: reflect.runtime.universe.MethodSymbol = method map
 *
 *  scala> map.typeSignature
 *  res0: reflect.runtime.universe.Type = [B, That](f: A => B)(implicit bf:
 *  scala.collection.generic.CanBuildFrom[Repr,B,That])That
 *
 *  scala> map.typeSignatureIn(typeOf[List[Int]])
 *  res1: reflect.runtime.universe.Type = [B, That](f: Int => B)(implicit bf:
 *  scala.collection.generic.CanBuildFrom[List[Int],B,That])That
 *
 *  scala> map.params
 *  res2: List[List[reflect.runtime.universe.Symbol]] = List(List(value f), List(value bf))
 *
 *  scala> val filter = map.params(0)(0)
 *  filter: reflect.runtime.universe.Symbol = value f
 *
 *  scala> filter.name
 *  res3: reflect.runtime.universe.Name = f
 *
 *  scala> filter.typeSignature
 *  res4: reflect.runtime.universe.Type = A => B
 *  }}}
 *
 *  === Gotcha #1: Overloaded methods ===
 *
 *  Be careful though, because overloaded methods are represented as instances of TermSymbol
 *  with multiple `alternatives` that have to be resolved manually. For example, a lookup
 *  for a member named `mkString` will produce not a MethodSymbol, but a TermSymbol:
 *
 *  {{{
 *  scala> list.typeSignature.member("mkString": TermName)
 *  res1: reflect.runtime.universe.Symbol = value mkString
 *
 *  scala> val mkString = list.typeSignature.member("mkString": TermName).asTerm
 *  mkString: reflect.runtime.universe.TermSymbol = value mkString
 *
 *  scala> mkString.isMethod
 *  res0: Boolean = false
 *
 *  scala> mkString.alternatives
 *  res1: List[reflect.runtime.universe.Symbol] = List(method mkString, method mkString, method mkString)
 *
 *  scala> mkString.alternatives foreach println
 *  method mkString
 *  method mkString
 *  method mkString
 *
 *  scala> mkString.alternatives foreach (alt => println(alt.typeSignature))
 *  => String
 *  (sep: String)String
 *  (start: String, sep: String, end: String)String
 *  }}}
 *
 *  Once one has a symbol, that symbol can be used for reflective invocations. For example,
 *  having a TermSymbol corresponding to a field it's possible to get or set a value of that field.
 *  Having a MethodSymbol makes it possible to invoke the corresponding methods. ClassSymbols
 *  can be instantiated. ModuleSymbols can provide corresponding singleton instances. This is described
 *  in detail on [[scala.reflect.api.package the reflection overview page]].
 *
 *  === Gotcha #2: Module classes ===
 *
 *  Internally the Scala compiler represents objects with two symbols: a module symbol and a module class symbol.
 *  The former is a term symbol, used everywhere a module is referenced (e.g. in singleton types or in expressions),
 *  while the latter is a type symbol, which carries the type signature (i.e. the member list) of the module.
 *  This implementation detail can be easily seen by compiling a trivial snippet of code. Invoking the Scala
 *  compiler on `object C` will generate C$.class. That's exactly the module class.
 *
 *  Note that module classes are different from companion classes. Say, for `case class C`, the compiler
 *  will generate three symbols: `type C`, `term C` and (another one) `type C`, where the first type `C`
 *  represents the class `C` (which contains auto-generated `copy`, `productPrefix`, `productArity` etc) and
 *  the second type `C` represents the signature of object `C` (which contains auto-generated factory,
 *  extractor etc). There won't be any name clashes, because the module class isn't added to the symbol table
 *  directly and is only available through `<module>.moduleClass`. For the sake of completeness, it is possible
 *  to go back from a module class to a module via `<module class>.module`.
 *
 *  Separation between modules and module classes is something that we might eliminate in the future, but for now
 *  this obscure implementation detail has to be taken into account when working with reflection. On the one hand,
 *  it is necessary to go to a module class to get a list of members for an object. On the other hand, it is
 *  necessary to go from a module class back to a module to get a singleton instance of an object. The latter
 *  scenario is described at Stack Overflow: [[http://stackoverflow.com/questions/12128783 How can I get the actual object referred to by Scala 2.10 reflection?]].
 */
trait Symbols { self: Universe =>

  /** The type of symbols representing declarations */
  type Symbol >: Null <: SymbolApi

  /** A tag that preserves the identity of the `Symbol` abstract type from erasure.
   *  Can be used for pattern matching, instance tests, serialization and likes.
   */
  implicit val SymbolTag: ClassTag[Symbol]

  /** The type of type symbols representing type, class, and trait declarations,
   *  as well as type parameters
   */
  type TypeSymbol >: Null <: Symbol with TypeSymbolApi

  /** A tag that preserves the identity of the `TypeSymbol` abstract type from erasure.
   *  Can be used for pattern matching, instance tests, serialization and likes.
   */
  implicit val TypeSymbolTag: ClassTag[TypeSymbol]

  /** The type of term symbols representing val, var, def, and object declarations as
   *  well as packages and value parameters.
   */
  type TermSymbol >: Null <: Symbol with TermSymbolApi

  /** A tag that preserves the identity of the `TermSymbol` abstract type from erasure.
   *  Can be used for pattern matching, instance tests, serialization and likes.
   */
  implicit val TermSymbolTag: ClassTag[TermSymbol]

  /** The type of method symbols representing def declarations */
  type MethodSymbol >: Null <: TermSymbol with MethodSymbolApi

  /** A tag that preserves the identity of the `MethodSymbol` abstract type from erasure.
   *  Can be used for pattern matching, instance tests, serialization and likes.
   */
  implicit val MethodSymbolTag: ClassTag[MethodSymbol]

  /** The type of module symbols representing object declarations */
  type ModuleSymbol >: Null <: TermSymbol with ModuleSymbolApi

  /** A tag that preserves the identity of the `ModuleSymbol` abstract type from erasure.
   *  Can be used for pattern matching, instance tests, serialization and likes.
   */
  implicit val ModuleSymbolTag: ClassTag[ModuleSymbol]

  /** The type of class symbols representing class and trait definitions */
  type ClassSymbol >: Null <: TypeSymbol with ClassSymbolApi

  /** A tag that preserves the identity of the `ClassSymbol` abstract type from erasure.
   *  Can be used for pattern matching, instance tests, serialization and likes.
   */
  implicit val ClassSymbolTag: ClassTag[ClassSymbol]

  /** The type of free terms introduced by reification */
  type FreeTermSymbol >: Null <: TermSymbol with FreeTermSymbolApi

  /** A tag that preserves the identity of the `FreeTermSymbol` abstract type from erasure.
   *  Can be used for pattern matching, instance tests, serialization and likes.
   */
  implicit val FreeTermSymbolTag: ClassTag[FreeTermSymbol]

  /** The type of free types introduced by reification */
  type FreeTypeSymbol >: Null <: TypeSymbol with FreeTypeSymbolApi

  /** A tag that preserves the identity of the `FreeTypeSymbol` abstract type from erasure.
   *  Can be used for pattern matching, instance tests, serialization and likes.
   */
  implicit val FreeTypeSymbolTag: ClassTag[FreeTypeSymbol]

  /** A special "missing" symbol */
  val NoSymbol: Symbol

  /** The API of symbols.
   *  The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
   */
  trait SymbolApi { this: Symbol =>

    /** The owner of this symbol. This is the symbol
     *  that directly contains the current symbol's definition.
     *  The `NoSymbol` symbol does not have an owner, and calling this method
     *  on one causes an internal error.
     *  The owner of the Scala root class [[scala.reflect.api.Mirror.RootClass]]
     *  and the Scala root object [[scala.reflect.api.Mirror.RootPackage]] is `NoSymbol`.
     *  Every other symbol has a chain of owners that ends in
     *  [[scala.reflect.api.Mirror.RootClass]].
     */
    def owner: Symbol

    /** The type of the symbol name.
     *  Can be either `TermName` or `TypeName` depending on whether this is a `TermSymbol` or a `TypeSymbol`.
     *
     *  Type name namespaces do not intersect with term name namespaces.
     *  This fact is reflected in different types for names of `TermSymbol` and `TypeSymbol`.
     */
    type NameType >: Null <: Name

    /** The name of the symbol as a member of the `Name` type.
     */
    def name: Name

    /** The encoded full path name of this symbol, where outer names and inner names
     *  are separated by periods.
     */
    def fullName: String

    /** Does this symbol represent the definition of a type?
     *  Note that every symbol is either a term or a type.
     *  So for every symbol `sym` (except for `NoSymbol`),
     *  either `sym.isTerm` is true or `sym.isType` is true.
     */
    def isType: Boolean = false

    /** This symbol cast to a TypeSymbol.
     *  @throws ScalaReflectionException if `isType` is false.
     */
    def asType: TypeSymbol = throw new ScalaReflectionException(s"$this is not a type")

    /** Does this symbol represent the definition of a term?
     *  Note that every symbol is either a term or a type.
     *  So for every symbol `sym` (except for `NoSymbol`),
     *  either `sym.isTerm` is true or `sym.isTerm` is true.
     */
    def isTerm: Boolean = false

    /** This symbol cast to a TermSymbol.
     *  @throws ScalaReflectionException if `isTerm` is false.
     */
    def asTerm: TermSymbol = throw new ScalaReflectionException(s"$this is not a term")

    /** Does this symbol represent the definition of a method?
     *  If yes, `isTerm` is also guaranteed to be true.
     */
    def isMethod: Boolean = false

    /** This symbol cast to a MethodSymbol.
     *  @throws ScalaReflectionException if `isMethod` is false.
     */
    def asMethod: MethodSymbol = {
      def overloadedMsg =
        "encapsulates multiple overloaded alternatives and cannot be treated as a method. "+
        "Consider invoking `<offending symbol>.asTerm.alternatives` and manually picking the required method"
      def vanillaMsg = "is not a method"
      val msg = if (isOverloadedMethod) overloadedMsg else vanillaMsg
      throw new ScalaReflectionException(s"$this $msg")
    }

    /** Used to provide a better error message for `asMethod` */
    protected def isOverloadedMethod = false

    /** Does this symbol represent the definition of a module (i.e. it
     *  results from an object definition?).
     *  If yes, `isTerm` is also guaranteed to be true.
     */
    def isModule: Boolean = false

    /** This symbol cast to a ModuleSymbol defined by an object definition.
     *  @throws ScalaReflectionException if `isModule` is false.
     */
    def asModule: ModuleSymbol = throw new ScalaReflectionException(s"$this is not a module")

    /** Does this symbol represent the definition of a class or trait?
     *  If yes, `isType` is also guaranteed to be true.
     */
    def isClass: Boolean = false

    /** Does this symbol represent the definition of a class implicitly associated
     *  with an object definition (module class in scala compiler parlance).
     *  If yes, `isType` is also guaranteed to be true.
     */
    def isModuleClass: Boolean = false

    /** This symbol cast to a ClassSymbol representing a class or trait.
     *  @throws ScalaReflectionException if `isClass` is false.
     */
    def asClass: ClassSymbol = throw new ScalaReflectionException(s"$this is not a class")

    /** Does this symbol represent a free term captured by reification?
     *  If yes, `isTerm` is also guaranteed to be true.
     */
    def isFreeTerm: Boolean = false

    /** This symbol cast to a free term symbol.
     *  @throws ScalaReflectionException if `isFreeTerm` is false.
     */
    def asFreeTerm: FreeTermSymbol = throw new ScalaReflectionException(s"$this is not a free term")

    /** Does this symbol represent a free type captured by reification?
     *  If yes, `isType` is also guaranteed to be true.
     */
    def isFreeType: Boolean = false

    /** This symbol cast to a free type symbol.
     *  @throws ScalaReflectionException if `isFreeType` is false.
     */
    def asFreeType: FreeTypeSymbol = throw new ScalaReflectionException(s"$this is not a free type")

    def newTermSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TermSymbol
    def newModuleAndClassSymbol(name: Name, pos: Position = NoPosition, flags: FlagSet = NoFlags): (ModuleSymbol, ClassSymbol)
    def newMethodSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): MethodSymbol
    def newTypeSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TypeSymbol
    def newClassSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): ClassSymbol

    /** Source file if this symbol is created during this compilation run,
     *  or a class file if this symbol is loaded from a *.class or *.jar.
     *
     *  The return type is [[scala.reflect.io.AbstractFile]], which belongs to an experimental part of Scala reflection.
     *  It should not be used unless you know what you are doing. In subsequent releases, this API will be refined
     *  and exposed as a part of scala.reflect.api.
     */
    def associatedFile: scala.reflect.io.AbstractFile

    /** A list of annotations attached to this Symbol.
     */
    def annotations: List[Annotation]

    /** For a class: the module or case class factory with the same name in the same package.
     *  For a module: the class with the same name in the same package.
     *  For all others: NoSymbol
     */
    def companionSymbol: Symbol

    /** The type signature of this symbol seen as a member of given type `site`.
     */
    def typeSignatureIn(site: Type): Type

    /** The type signature of this symbol.
     *  Note if the symbol is a member of a class, one almost always is interested
     *  in `typeSignatureIn` with a site type instead.
     */
    def typeSignature: Type

    /** Returns all symbols overriden by this symbol. */
    def allOverriddenSymbols: List[Symbol]

    /******************* tests *******************/

    /** Does this symbol represent a synthetic (i.e. a compiler-generated) entity?
     *  Examples of synthetic entities are accessors for vals and vars
     *  or mixin constructors in trait implementation classes.
     */
    def isSynthetic: Boolean

    /** Does this symbol represent an implementation artifact that isn't meant for public use?
     *  Examples of such artifacts are erasure bridges and $outer fields.
     */
    def isImplementationArtifact: Boolean

    /** Does this symbol represent a local declaration or definition?
     *
     *  If yes, either `isPrivate` or `isProtected` are guaranteed to be true.
     *  Local symbols can only be accessed from the same object instance.
     *
     *  If yes, `privateWithin` might tell more about this symbol's visibility scope.
     */
    def isLocal: Boolean

    /** Does this symbol represent a private declaration or definition?
     *  If yes, `privateWithin` might tell more about this symbol's visibility scope.
     */
    def isPrivate: Boolean

    /** Does this symbol represent a protected declaration or definition?
     *  If yes, `privateWithin` might tell more about this symbol's visibility scope.
     */
    def isProtected: Boolean

    /** Does this symbol represent a public declaration or definition?
     */
    def isPublic: Boolean

    /**
     * Set when symbol has a modifier of the form private[X], NoSymbol otherwise.
     *
     *  Access level encoding: there are three scala flags (PRIVATE, PROTECTED,
     *  and LOCAL) which combine with value privateWithin (the "foo" in private[foo])
     *  to define from where an entity can be accessed.  The meanings are as follows:
     *
     *  PRIVATE     access restricted to class only.
     *  PROTECTED   access restricted to class and subclasses only.
     *  LOCAL       can only be set in conjunction with PRIVATE or PROTECTED.
     *              Further restricts access to the same object instance.
     *
     *  In addition, privateWithin can be used to set a visibility barrier.
     *  When set, everything contained in the named enclosing package or class
     *  has access.  It is incompatible with PRIVATE or LOCAL, but is additive
     *  with PROTECTED (i.e. if either the flags or privateWithin allow access,
     *  then it is allowed.)
     *
     *  The java access levels translate as follows:
     *
     *  java private:     isPrivate                  && (privateWithin == NoSymbol)
     *  java package:     !isPrivate && !isProtected && (privateWithin == enclosingPackage)
     *  java protected:   isProtected                && (privateWithin == enclosingPackage)
     *  java public:      !isPrivate && !isProtected && (privateWithin == NoSymbol)
     */
    def privateWithin: Symbol

    /** Does this symbol represent the definition of a package?
     *  If yes, `isTerm` is also guaranteed to be true.
     */
    def isPackage: Boolean

    /** Does this symbol represent a package class?
     *  If yes, `isClass` is also guaranteed to be true.
     */
    def isPackageClass: Boolean

    /** Does this symbol or its underlying type represent a typechecking error?
     */
    def isErroneous : Boolean

    /** Is this symbol static (i.e. with no outer instance)?
     *  Q: When exactly is a sym marked as STATIC?
     *  A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep.
     *  http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6
     */
    def isStatic: Boolean

    /** Is this symbol final?
     */
    def isFinal: Boolean

    /** Is this symbol overriding something?
     */
    def isOverride: Boolean

    /** Is this symbol labelled as "abstract override"?
     */
    def isAbstractOverride: Boolean

    /** Is this symbol a macro?
     */
    def isMacro: Boolean

    /** Is this symbol a parameter (either a method parameter or a type parameter)?
     */
    def isParameter: Boolean

    /** Is this symbol a specialized type parameter or a generated specialized member?
     */
    def isSpecialized: Boolean

    /** Is this symbol defined by Java?
     */
    def isJava: Boolean

    /** Does this symbol represent an implicit value, definition, class or parameter?
     */
    def isImplicit: Boolean

    /******************* helpers *******************/

    /** Provides an alternate if symbol is a NoSymbol.
     */
    def orElse(alt: => Symbol): Symbol

    /** Filters the underlying alternatives (or a single-element list
     *  composed of the symbol itself if the symbol is not overloaded).
     *  Returns an overloaded symbol is there are multiple matches.
     *  Returns a NoSymbol if there are no matches.
     */
    def filter(cond: Symbol => Boolean): Symbol

    /** If this is a NoSymbol, returns NoSymbol, otherwise
     *  returns the result of applying `f` to this symbol.
     */
    def map(f: Symbol => Symbol): Symbol

    /** Does the same as `filter`, but crashes if there are multiple matches.
     */
    def suchThat(cond: Symbol => Boolean): Symbol
  }

  /** The API of term symbols.
   *  The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
   */
  trait TermSymbolApi extends SymbolApi { this: TermSymbol =>
    /** Term symbols have their names of type `TermName`.
     */
    final type NameType = TermName

    final override def isTerm = true
    final override def asTerm = this

    /** Is this symbol introduced as `val`?
     */
    def isVal: Boolean

    /** Does this symbol denote a stable value? */
    def isStable: Boolean

    /** Is this symbol introduced as `var`?
     */
    def isVar: Boolean

    /** Does this symbol represent a getter or a setter?
     */
    def isAccessor: Boolean

    /** Does this symbol represent a getter of a field?
     *  If yes, `isMethod` is also guaranteed to be true.
     */
    def isGetter: Boolean

    /** Does this symbol represent a setter of a field?
     *  If yes, `isMethod` is also guaranteed to be true.
     */
    def isSetter: Boolean

    /** Does this symbol represent an overloaded method?
     *  If yes, `isMethod` is false, and the list of the enclosed alternatives can be found out via `alternatives`.
     */
    def isOverloaded   : Boolean

    /** Does this symbol represent a lazy value?
     */
    def isLazy: Boolean

    /** The overloaded alternatives of this symbol */
    def alternatives: List[Symbol]

    /** Used to provide a better error message for `asMethod` */
    override protected def isOverloadedMethod = alternatives exists (_.isMethod)

    /** Backing field for an accessor method, NoSymbol for all other term symbols.
     */
    def accessed: Symbol

    /** Getter method for a backing field of a val or a val, NoSymbol for all other term symbols.
     */
    def getter: Symbol

    /** Setter method for a backing field of a val or a val, NoSymbol for all other term symbols.
     */
    def setter: Symbol

    /** Does this symbol represent a field of a class
     *  that was generated from a parameter of that class?
     */
    def isParamAccessor: Boolean

    /** Does this symbol represent a field of a case class
     *  that corresponds to a parameter in the first parameter list of the
     *  primary constructor of that class?
     */
    def isCaseAccessor: Boolean

    /** Does this symbol represent a parameter with a default value?
     */
    def isParamWithDefault: Boolean

    /** Does this symbol represent a by-name parameter?
     */
    def isByNameParam: Boolean
  }

  /** The API of type symbols.
   *  The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
   */
  trait TypeSymbolApi extends SymbolApi { this: TypeSymbol =>
    /** Type symbols have their names of type `TypeName`.
     */
    final type NameType = TypeName

    /** The type constructor corresponding to this type symbol.
     *  This is different from `toType` in that type parameters
     *  are part of results of `toType`, but not of `toTypeConstructor`.
     *
     *  Example: Given a class declaration `class C[T] { ... } `, that generates a symbol
     *  `C`. Then `C.toType` is the type `C[T]`, but `C.toTypeConstructor` is `C`.
     */
    def toTypeConstructor: Type

    /** A type reference that refers to this type symbol seen
     *  as a member of given type `site`.
     */
    def toTypeIn(site: Type): Type

    /**  A type reference that refers to this type symbol
      *  Note if symbol is a member of a class, one almost always is interested
      *  in `asTypeIn` with a site type instead.
      *
      *  Example: Given a class declaration `class C[T] { ... } `, that generates a symbol
      *  `C`. Then `C.toType` is the type `C[T]`.
      *
      *  By contrast, `C.typeSignature` would be a type signature of form
      *  `PolyType(ClassInfoType(...))` that describes type parameters, value
      *  parameters, parent types, and members of `C`.
      */
    def toType: Type

    final override def isType = true
    final override def asType = this

    /** Is the type parameter represented by this symbol contravariant?
     */
    def isContravariant : Boolean

    /** Is the type parameter represented by this symbol contravariant?
     */
    def isCovariant     : Boolean

    /** Does this symbol represent the definition of a skolem?
     *  Skolems are used during typechecking to represent type parameters viewed from inside their scopes.
     */
    def isSkolem       : Boolean

    /** Does this symbol represent the definition of a type alias?
     */
    def isAliasType    : Boolean

    /** Does this symbol represent the definition of an abstract type?
     */
    def isAbstractType : Boolean

    /** Does this symbol represent an existentially bound type?
     */
    def isExistential  : Boolean

    /** For a polymorphic type, its type parameters, the empty list for all other types */
    def typeParams: List[Symbol]
  }

  /** The API of method symbols.
   *  The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
   */
  trait MethodSymbolApi extends TermSymbolApi { this: MethodSymbol =>
    final override def isMethod = true
    final override def asMethod = this

    /** Does this method represent a constructor?
     *
     *  If `owner` is a class, then this is a vanilla JVM constructor.
     *  If `owner` is a trait, then this is a mixin constructor.
     */
    def isConstructor: Boolean

    /** Does this symbol denote the primary constructor of its enclosing class? */
    def isPrimaryConstructor: Boolean

    /** For a polymorphic method, its type parameters, the empty list for all other methods */
    def typeParams: List[Symbol]

    /** All parameter lists of the method.
     *  The name ending with "ss" indicates that the result type is a list of lists.
     *
     *  Can be used to distinguish nullary methods and methods with empty parameter lists.
     *  For a nullary method, returns the empty list (i.e. `List()`).
     *  For a method with an empty parameter list, returns a list that contains the empty list (i.e. `List(List())`).
     */
    def paramss: List[List[Symbol]]

    /** Does this method support variable length argument lists?
     */
    def isVarargs: Boolean

    /** The return type of the method */
    def returnType: Type
  }

  /** The API of module symbols.
   *  The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
   */
  trait ModuleSymbolApi extends TermSymbolApi { this: ModuleSymbol =>
    /** The class implicitly associated with the object definition.
     *  One can go back from a module class to the associated module symbol
     *  by inspecting its `selfType.termSymbol`.
     */
    def moduleClass: Symbol // needed for tree traversals
    // when this becomes `moduleClass: ClassSymbol`, it will be the happiest day in my life

    final override def isModule = true
    final override def asModule = this
  }

  /** The API of class symbols.
   *  The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
   */
  trait ClassSymbolApi extends TypeSymbolApi { this: ClassSymbol =>
    final override def isClass = true
    final override def asClass = this

    /** Does this symbol represent the definition of a primitive class?
     *  Namely, is it one of [[scala.Double]], [[scala.Float]], [[scala.Long]], [[scala.Int]], [[scala.Char]],
     *  [[scala.Short]], [[scala.Byte]], [[scala.Unit]] or [[scala.Boolean]]?
     */
    def isPrimitive: Boolean

    /** Does this symbol represent the definition of a numeric value class?
     *  Namely, is it one of [[scala.Double]], [[scala.Float]], [[scala.Long]], [[scala.Int]], [[scala.Char]],
     *  [[scala.Short]], [[scala.Byte]], [[scala.Unit]] or [[scala.Boolean]]?
     */
    def isNumeric: Boolean

    /** Does this symbol represent the definition of a custom value class?
     *  Namely, is AnyVal among its parent classes?
     */
    def isDerivedValueClass: Boolean

    /** Does this symbol represent a trait?
     */
    def isTrait: Boolean

    /** Does this symbol represent an abstract class?
     */
    def isAbstractClass: Boolean

    /** Does this symbol represent a case class?
     */
    def isCaseClass: Boolean

    /** Does this symbol represent a sealed class?
     */
    def isSealed: Boolean

    /** If this is a sealed class, its known direct subclasses.
     *  Otherwise, the empty set.
     */
    def knownDirectSubclasses: Set[Symbol]

    /** The list of all base classes of this type (including its own typeSymbol)
     *  in reverse linearization order, starting with the class itself and ending
     *  in class Any.
     */
    def baseClasses: List[Symbol]

    /** The module corresponding to this module class,
     *  or NoSymbol if this symbol is not a module class.
     */
    def module: Symbol

    /** If this symbol is a class or trait, its self type, otherwise the type
     *  of the symbol itself.
     */
    def selfType: Type

    /** The type `C.this`, where `C` is the current class */
    def thisPrefix: Type

    /** For a polymorphic class/trait, its type parameters, the empty list for all other classes/trait */
    def typeParams: List[Symbol]
  }

  /** The API of free term symbols.
   *  The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
   */
  trait FreeTermSymbolApi extends TermSymbolApi { this: FreeTermSymbol =>
    final override def isFreeTerm = true
    final override def asFreeTerm = this

    /** The place where this symbol has been spawned */
    def origin: String

    /** The valus this symbol refers to */
    def value: Any
  }

  /** The API of free type symbols.
   *  The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
   */
  trait FreeTypeSymbolApi extends TypeSymbolApi { this: FreeTypeSymbol =>
    final override def isFreeType = true
    final override def asFreeType = this

    /** The place where this symbol has been spawned */
    def origin: String
  }
}