summaryrefslogblamecommitdiff
path: root/src/library/scala/reflect/base/TypeTags.scala
blob: 37e0c4f02f3bde95fe71fb21b94c61d0138dc365 (plain) (tree)
1
2
3
4
5
6
7
8
9
                            
                                



                          
            
 
                                    
                                   





                                                                                                             

                   
                                                           
                                                                                                                       
  

                                                                                                                           

                                                                                                               
  

                                                                                                    
                                                                                         
  

                                                                                                     




                                                                                                                 




                                                                                      
                                   



                                                                
                                    

                                                                                                                         
  
                                 
  
                                                                                             


                                                                                                                     

                                                                                               
                        

                                                                                               


                                                                                                                      
                                                                                                                              

                                                                                     

                                                                                                                       
                                                                                          
                                                                                                               



                                                                            


                                             
                                                                                                    
                                                                                                             



                                                                                       
                                                                                                        


                                                                                                                     
                                                                                                   
  
                                                                                                     
                                                                                                                 
                                                                                                                  





                                                                                                                        


                                  

                      
     
                                                                                                        



                                                                                                                            
                                         
     

                                                                         
                      
                                                                                      
                 

                                 

                                                                                                                                                                          
                                                               
                                                      

   















                                                                 
 
                                                                                    
                            















                                                                                      

       
                                                                       

   
                                                                                                      
                                     
                                                                                          
                                                                                      
                                                             
     
                                                                                      








                                                                                                                                                 
                                                                         


                                                                                           
                                                              


                                                                                                                                                              


                  









                                                                                                                

                                                                                                               


                                                                                                                
 

                                                                                









                                                                   

                                                                  
                                                                  

                                                                   
                                                                                  
       

                                                                   

   
                                                                                                                            

                                                                                               
                                                         
     
                                                                                     

   






                                                                                                                                                           
                                      
                                                                                     


                 
                                                            
                                                  

                                                        
                                                                     
                                                           
 














                                                                                                           
                                      

   
/* NSC -- new Scala compiler
 * Copyright 2005-2012 LAMP/EPFL
 * @author  Martin Odersky
 */

package scala.reflect
package base

import java.lang.{ Class => jClass }
import language.implicitConversions

/**
 * Type tags encapsulate a representation of type T.
 * They are supposed to replace the pre-2.10 concept of a [[scala.reflect.Manifest]].
 * TypeTags are much better integrated with reflection than manifests are, and are consequently much simpler.
 *
 * === Overview ===
 *
 * Type tags are organized in a hierarchy of three classes:
 * [[scala.reflect.ClassTag]], [[scala.reflect.base.Universe#TypeTag]] and [[scala.reflect.base.Universe#WeakTypeTag]].
 *
 * A [[scala.reflect.ClassTag]] carries a runtime class that corresponds to the source type T.
 * As of such, it possesses the knowledge about how to build single- and multi-dimensional arrays of elements of that type.
 * It guarantees that the source type T did not to contain any references to type parameters or abstract types.
 * [[scala.reflect.ClassTag]] corresponds to a previous notion of [[scala.reflect.ClassManifest]].
 *
 * A [[scala.reflect.base.Universe#WeakTypeTag]] value wraps a full Scala type in its tpe field.
 * A [[scala.reflect.base.Universe#TypeTag]] value is an [[scala.reflect.base.Universe#WeakTypeTag]]
 * that is guaranteed not to contain any references to type parameters or abstract types.
 *
 * [Eugene++] also mention sensitivity to prefixes, i.e. that rb.TypeTag is different from ru.TypeTag
 * [Eugene++] migratability between mirrors and universes is also worth mentioning
 *
 * === Splicing ===
 *
 * Tags can be spliced, i.e. if compiler generates a tag for a type that contains references to tagged
 * type parameters or abstract type members, it will retrieve the corresponding tag and embed it into the result.
 * An example that illustrates the TypeTag embedding, consider the following function:
 *
 *   import reflect.mirror._
 *     def f[T: TypeTag, U] = {
 *       type L = T => U
 *       implicitly[WeakTypeTag[L]]
 *     }
 *
 * Then a call of f[String, Int] will yield a result of the form
 *
 *   WeakTypeTag(<[ String => U ]>).
 *
 * Note that T has been replaced by String, because it comes with a TypeTag in f, whereas U was left as a type parameter.
 *
 * === WeakTypeTag vs TypeTag ===
 *
 * Be careful with WeakTypeTag, because it will reify types even if these types are abstract.
 * This makes it easy to forget to tag one of the methods in the call chain and discover it much later in the runtime
 * by getting cryptic errors far away from their source. For example, consider the following snippet:
 *
 *   def bind[T: WeakTypeTag](name: String, value: T): IR.Result = bind((name, value))
 *   def bind(p: NamedParam): IR.Result                          = bind(p.name, p.tpe, p.value)
 *   object NamedParam {
 *     implicit def namedValue[T: WeakTypeTag](name: String, x: T): NamedParam = apply(name, x)
 *     def apply[T: WeakTypeTag](name: String, x: T): NamedParam = new Typed[T](name, x)
 *   }
 *
 * This fragment of Scala REPL implementation defines a `bind` function that carries a named value along with its type
 * into the heart of the REPL. Using a [[scala.reflect.base.Universe#WeakTypeTag]] here is reasonable, because it is desirable
 * to work with all types, even if they are type parameters or abstract type members.
 *
 * However if any of the three `WeakTypeTag` context bounds is omitted, the resulting code will be incorrect,
 * because the missing `WeakTypeTag` will be transparently generated by the compiler, carrying meaningless information.
 * Most likely, this problem will manifest itself elsewhere, making debugging complicated.
 * If `WeakTypeTag` context bounds were replaced with `TypeTag`, then such errors would be reported statically.
 * But in that case we wouldn't be able to use `bind` in arbitrary contexts.
 *
 * === Backward compatibility ===
 *
 * Type tags correspond loosely to manifests.
 *
 * More precisely:
 * The previous notion of a [[scala.reflect.ClassManifest]] corresponds to a scala.reflect.ClassTag,
 * The previous notion of a [[scala.reflect.Manifest]] corresponds to scala.reflect.runtime.universe.TypeTag,
 *
 * In Scala 2.10, manifests are deprecated, so it's adviseable to migrate them to tags,
 * because manifests might be removed in the next major release.
 *
 * In most cases it will be enough to replace ClassManifests with ClassTags and Manifests with TypeTags,
 * however there are a few caveats:
 *
 * 1) The notion of OptManifest is no longer supported. Tags can reify arbitrary types, so they are always available.
 *    // [Eugene++] it might be useful, though, to guard against abstractness of the incoming type.
 *
 * 2) There's no equivalent for AnyValManifest. Consider comparing your tag with one of the base tags
 *    (defined in the corresponding companion objects) to find out whether it represents a primitive value class.
 *    You can also use `<tag>.tpe.typeSymbol.isPrimitiveValueClass` for that purpose (requires scala-reflect.jar).
 *
 * 3) There's no replacement for factory methods defined in `ClassManifest` and `Manifest` companion objects.
 *    Consider assembling corresponding types using reflection API provided by Java (for classes) and Scala (for types).
 *
 * 4) Certain manifest functions (such as `<:<`, `>:>` and `typeArguments`) weren't included in the tag API.
 *    Consider using reflection API provided by Java (for classes) and Scala (for types) instead.
 */
trait TypeTags { self: Universe =>

  import definitions._

  /**
   * If an implicit value of type u.WeakTypeTag[T] is required, the compiler will make one up on demand.
   * The implicitly created value contains in its tpe field a value of type u.Type that is a reflective representation of T.
   * In that value, any occurrences of type parameters or abstract types U
   * which come themselves with a TypeTag are represented by the type referenced by that TypeTag.
   *
   * @see [[scala.reflect.base.TypeTags]]
   */
  @annotation.implicitNotFound(msg = "No WeakTypeTag available for ${T}")
  trait WeakTypeTag[T] extends Equals with Serializable {
    val mirror: Mirror
    def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # WeakTypeTag[T]
    def tpe: Type

    /** case class accessories */
    override def canEqual(x: Any) = x.isInstanceOf[WeakTypeTag[_]]
    override def equals(x: Any) = x.isInstanceOf[WeakTypeTag[_]] && this.mirror == x.asInstanceOf[WeakTypeTag[_]].mirror && this.tpe == x.asInstanceOf[WeakTypeTag[_]].tpe
    override def hashCode = mirror.hashCode * 31 + tpe.hashCode
    override def toString = "WeakTypeTag[" + tpe + "]"
  }

  object WeakTypeTag {
    val Byte    : WeakTypeTag[scala.Byte]       = TypeTag.Byte
    val Short   : WeakTypeTag[scala.Short]      = TypeTag.Short
    val Char    : WeakTypeTag[scala.Char]       = TypeTag.Char
    val Int     : WeakTypeTag[scala.Int]        = TypeTag.Int
    val Long    : WeakTypeTag[scala.Long]       = TypeTag.Long
    val Float   : WeakTypeTag[scala.Float]      = TypeTag.Float
    val Double  : WeakTypeTag[scala.Double]     = TypeTag.Double
    val Boolean : WeakTypeTag[scala.Boolean]    = TypeTag.Boolean
    val Unit    : WeakTypeTag[scala.Unit]       = TypeTag.Unit
    val Any     : WeakTypeTag[scala.Any]        = TypeTag.Any
    val AnyVal  : WeakTypeTag[scala.AnyVal]     = TypeTag.AnyVal
    val AnyRef  : WeakTypeTag[scala.AnyRef]     = TypeTag.AnyRef
    val Object  : WeakTypeTag[java.lang.Object] = TypeTag.Object
    val Nothing : WeakTypeTag[scala.Nothing]    = TypeTag.Nothing
    val Null    : WeakTypeTag[scala.Null]       = TypeTag.Null

    def apply[T](mirror1: MirrorOf[self.type], tpec1: TypeCreator): WeakTypeTag[T] =
      tpec1(mirror1) match {
        case ByteTpe    => WeakTypeTag.Byte.asInstanceOf[WeakTypeTag[T]]
        case ShortTpe   => WeakTypeTag.Short.asInstanceOf[WeakTypeTag[T]]
        case CharTpe    => WeakTypeTag.Char.asInstanceOf[WeakTypeTag[T]]
        case IntTpe     => WeakTypeTag.Int.asInstanceOf[WeakTypeTag[T]]
        case LongTpe    => WeakTypeTag.Long.asInstanceOf[WeakTypeTag[T]]
        case FloatTpe   => WeakTypeTag.Float.asInstanceOf[WeakTypeTag[T]]
        case DoubleTpe  => WeakTypeTag.Double.asInstanceOf[WeakTypeTag[T]]
        case BooleanTpe => WeakTypeTag.Boolean.asInstanceOf[WeakTypeTag[T]]
        case UnitTpe    => WeakTypeTag.Unit.asInstanceOf[WeakTypeTag[T]]
        case AnyTpe     => WeakTypeTag.Any.asInstanceOf[WeakTypeTag[T]]
        case AnyValTpe  => WeakTypeTag.AnyVal.asInstanceOf[WeakTypeTag[T]]
        case AnyRefTpe  => WeakTypeTag.AnyRef.asInstanceOf[WeakTypeTag[T]]
        case ObjectTpe  => WeakTypeTag.Object.asInstanceOf[WeakTypeTag[T]]
        case NothingTpe => WeakTypeTag.Nothing.asInstanceOf[WeakTypeTag[T]]
        case NullTpe    => WeakTypeTag.Null.asInstanceOf[WeakTypeTag[T]]
        case _          => new WeakTypeTagImpl[T](mirror1.asInstanceOf[Mirror], tpec1)
      }

    def unapply[T](ttag: WeakTypeTag[T]): Option[Type] = Some(ttag.tpe)
  }

  private class WeakTypeTagImpl[T](val mirror: Mirror, val tpec: TypeCreator) extends WeakTypeTag[T] {
    lazy val tpe: Type = tpec(mirror)
    def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # WeakTypeTag[T] = {
      val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]]
      otherMirror.universe.WeakTypeTag[T](otherMirror1, tpec)
    }
    private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = false)
  }

  /**
   * If an implicit value of type u.TypeTag[T] is required, the compiler will make one up on demand following the same procedure as for TypeTags.
   * However, if the resulting type still contains references to type parameters or abstract types, a static error results.
   *
   * @see [[scala.reflect.base.TypeTags]]
   */
  @annotation.implicitNotFound(msg = "No TypeTag available for ${T}")
  trait TypeTag[T] extends WeakTypeTag[T] with Equals with Serializable {
    override def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # TypeTag[T]

    /** case class accessories */
    override def canEqual(x: Any) = x.isInstanceOf[TypeTag[_]]
    override def equals(x: Any) = x.isInstanceOf[TypeTag[_]] && this.mirror == x.asInstanceOf[TypeTag[_]].mirror && this.tpe == x.asInstanceOf[TypeTag[_]].tpe
    override def hashCode = mirror.hashCode * 31 + tpe.hashCode
    override def toString = "TypeTag[" + tpe + "]"
  }

  object TypeTag {
    val Byte:    TypeTag[scala.Byte]       = new PredefTypeTag[scala.Byte]       (ByteTpe,    _.TypeTag.Byte)
    val Short:   TypeTag[scala.Short]      = new PredefTypeTag[scala.Short]      (ShortTpe,   _.TypeTag.Short)
    val Char:    TypeTag[scala.Char]       = new PredefTypeTag[scala.Char]       (CharTpe,    _.TypeTag.Char)
    val Int:     TypeTag[scala.Int]        = new PredefTypeTag[scala.Int]        (IntTpe,     _.TypeTag.Int)
    val Long:    TypeTag[scala.Long]       = new PredefTypeTag[scala.Long]       (LongTpe,    _.TypeTag.Long)
    val Float:   TypeTag[scala.Float]      = new PredefTypeTag[scala.Float]      (FloatTpe,   _.TypeTag.Float)
    val Double:  TypeTag[scala.Double]     = new PredefTypeTag[scala.Double]     (DoubleTpe,  _.TypeTag.Double)
    val Boolean: TypeTag[scala.Boolean]    = new PredefTypeTag[scala.Boolean]    (BooleanTpe, _.TypeTag.Boolean)
    val Unit:    TypeTag[scala.Unit]       = new PredefTypeTag[scala.Unit]       (UnitTpe,    _.TypeTag.Unit)
    val Any:     TypeTag[scala.Any]        = new PredefTypeTag[scala.Any]        (AnyTpe,     _.TypeTag.Any)
    val AnyVal:  TypeTag[scala.AnyVal]     = new PredefTypeTag[scala.AnyVal]     (AnyValTpe,  _.TypeTag.AnyVal)
    val AnyRef:  TypeTag[scala.AnyRef]     = new PredefTypeTag[scala.AnyRef]     (AnyRefTpe,  _.TypeTag.AnyRef)
    val Object:  TypeTag[java.lang.Object] = new PredefTypeTag[java.lang.Object] (ObjectTpe,  _.TypeTag.Object)
    val Nothing: TypeTag[scala.Nothing]    = new PredefTypeTag[scala.Nothing]    (NothingTpe, _.TypeTag.Nothing)
    val Null:    TypeTag[scala.Null]       = new PredefTypeTag[scala.Null]       (NullTpe,    _.TypeTag.Null)

    def apply[T](mirror1: MirrorOf[self.type], tpec1: TypeCreator): TypeTag[T] =
      tpec1(mirror1) match {
        case ByteTpe    => TypeTag.Byte.asInstanceOf[TypeTag[T]]
        case ShortTpe   => TypeTag.Short.asInstanceOf[TypeTag[T]]
        case CharTpe    => TypeTag.Char.asInstanceOf[TypeTag[T]]
        case IntTpe     => TypeTag.Int.asInstanceOf[TypeTag[T]]
        case LongTpe    => TypeTag.Long.asInstanceOf[TypeTag[T]]
        case FloatTpe   => TypeTag.Float.asInstanceOf[TypeTag[T]]
        case DoubleTpe  => TypeTag.Double.asInstanceOf[TypeTag[T]]
        case BooleanTpe => TypeTag.Boolean.asInstanceOf[TypeTag[T]]
        case UnitTpe    => TypeTag.Unit.asInstanceOf[TypeTag[T]]
        case AnyTpe     => TypeTag.Any.asInstanceOf[TypeTag[T]]
        case AnyValTpe  => TypeTag.AnyVal.asInstanceOf[TypeTag[T]]
        case AnyRefTpe  => TypeTag.AnyRef.asInstanceOf[TypeTag[T]]
        case ObjectTpe  => TypeTag.Object.asInstanceOf[TypeTag[T]]
        case NothingTpe => TypeTag.Nothing.asInstanceOf[TypeTag[T]]
        case NullTpe    => TypeTag.Null.asInstanceOf[TypeTag[T]]
        case _          => new TypeTagImpl[T](mirror1.asInstanceOf[Mirror], tpec1)
      }

    def unapply[T](ttag: TypeTag[T]): Option[Type] = Some(ttag.tpe)
  }

  private class TypeTagImpl[T](mirror: Mirror, tpec: TypeCreator) extends WeakTypeTagImpl[T](mirror, tpec) with TypeTag[T] {
    override def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # TypeTag[T] = {
      val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]]
      otherMirror.universe.TypeTag[T](otherMirror1, tpec)
    }
    private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true)
  }

  private class PredefTypeCreator[T](copyIn: Universe => Universe # TypeTag[T]) extends TypeCreator {
    def apply[U <: Universe with Singleton](m: MirrorOf[U]): U # Type = {
      copyIn(m.universe).asInstanceOf[U # TypeTag[T]].tpe
    }
  }

  private class PredefTypeTag[T](_tpe: Type, copyIn: Universe => Universe # TypeTag[T]) extends TypeTagImpl[T](rootMirror, new PredefTypeCreator(copyIn)) {
    override lazy val tpe: Type = _tpe
    private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true)
  }

  // incantations
  def weakTypeTag[T](implicit attag: WeakTypeTag[T]) = attag
  def typeTag[T](implicit ttag: TypeTag[T]) = ttag

  // big thanks to Viktor Klang for this brilliant idea!
  def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = attag.tpe
  def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
}

private[scala] class SerializedTypeTag(var tpec: TypeCreator, var concrete: Boolean) extends Serializable {
  private def writeObject(out: java.io.ObjectOutputStream): Unit = {
    out.writeObject(tpec)
    out.writeBoolean(concrete)
  }

  private def readObject(in: java.io.ObjectInputStream): Unit = {
    tpec = in.readObject().asInstanceOf[TypeCreator]
    concrete = in.readBoolean()
  }

  private def readResolve(): AnyRef = {
    import scala.reflect.basis._
    if (concrete) TypeTag(rootMirror, tpec)
    else WeakTypeTag(rootMirror, tpec)
  }
}