alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (GenTypes.scala)

This example Scala source code file (GenTypes.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Scala source code examples by using tags.

All credit for the original source code belongs to scala-lang.org; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Scala tags/keywords

annotatedtype, emptytree, list, reflection, reflectruntimeuniverse, reify, select, singletype, thistype, tree, type, typeref

The GenTypes.scala Scala example source code

package scala.reflect.reify
package codegen

trait GenTypes {
  self: Reifier =>

  import global._
  import definitions._
  private val runDefinitions = currentRun.runDefinitions
  import runDefinitions.{ReflectRuntimeUniverse, ReflectRuntimeCurrentMirror, _}

  /**
   *  Reify a type.
   *  For internal use only, use `reified` instead.
   */
  def reifyType(tpe: Type): Tree = {
    assert(tpe != null, "tpe is null")

    if (tpe.isErroneous)
      CannotReifyErroneousReifee(tpe)
    if (tpe.isLocalToReifee)
      CannotReifyType(tpe)

    // this is a very special case. see the comments below for more info.
    if (isSemiConcreteTypeMember(tpe))
      return reifySemiConcreteTypeMember(tpe)

    // SI-6242: splicing might violate type bounds
    val spliced = spliceType(tpe)
    if (spliced != EmptyTree)
      return spliced

    val tsym = tpe.typeSymbolDirect
    if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic)
      Select(Select(reify(tsym), nme.asType), nme.toTypeConstructor)
    else tpe match {
      case tpe : NoType.type =>
        reifyMirrorObject(tpe)
      case tpe : NoPrefix.type =>
        reifyMirrorObject(tpe)
      case tpe @ ThisType(root) if root.isRoot =>
        mirrorBuildCall(nme.thisPrefix, mirrorMirrorSelect(nme.RootClass))
      case tpe @ ThisType(empty) if empty.isEmptyPackageClass =>
        mirrorBuildCall(nme.thisPrefix, mirrorMirrorSelect(nme.EmptyPackageClass))
      case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic =>
        val module = reify(clazz.sourceModule)
        val moduleClass = Select(Select(module, nme.asModule), nme.moduleClass)
        mirrorBuildCall(nme.ThisType, moduleClass)
      case tpe @ ThisType(sym) =>
        reifyBuildCall(nme.ThisType, sym)
      case tpe @ SuperType(thistpe, supertpe) =>
        reifyBuildCall(nme.SuperType, thistpe, supertpe)
      case tpe @ SingleType(pre, sym) =>
        reifyBuildCall(nme.SingleType, pre, sym)
      case tpe @ ConstantType(value) =>
        mirrorBuildCall(nme.ConstantType, reifyProduct(value))
      case tpe @ TypeRef(pre, sym, args) =>
        reifyBuildCall(nme.TypeRef, pre, sym, args)
      case tpe @ TypeBounds(lo, hi) =>
        reifyBuildCall(nme.TypeBounds, lo, hi)
      case tpe @ NullaryMethodType(restpe) =>
        reifyBuildCall(nme.NullaryMethodType, restpe)
      case tpe @ AnnotatedType(anns, underlying) =>
        reifyAnnotatedType(tpe)
      case _ =>
        reifyToughType(tpe)
    }
  }

  /** Keeps track of whether this reification contains abstract type parameters */
  def reificationIsConcrete: Boolean = state.reificationIsConcrete

  def spliceType(tpe: Type): Tree = {
    if (tpe.isSpliceable && !(boundSymbolsInCallstack contains tpe.typeSymbol)) {
      if (reifyDebug) println("splicing " + tpe)

      val tagFlavor = if (concrete) tpnme.TypeTag.toString else tpnme.WeakTypeTag.toString
      // if this fails, it might produce the dreaded "erroneous or inaccessible type" error
      // to find out the whereabouts of the error run scalac with -Ydebug
      if (reifyDebug) println("launching implicit search for %s.%s[%s]".format(universe, tagFlavor, tpe))
      val result =
        typer.resolveTypeTag(defaultErrorPosition, universe.tpe, tpe, concrete = concrete, allowMaterialization = false) match {
          case failure if failure.isEmpty =>
            if (reifyDebug) println("implicit search was fruitless")
            if (reifyDebug) println("trying to splice as manifest")
            val splicedAsManifest = spliceAsManifest(tpe)
            if (splicedAsManifest.isEmpty) {
              if (reifyDebug) println("no manifest in scope")
              EmptyTree
            } else {
              if (reifyDebug) println("successfully spliced as manifest: " + splicedAsManifest)
              splicedAsManifest
            }
          case success =>
            if (reifyDebug) println("implicit search has produced a result: " + success)
            state.reificationIsConcrete &= concrete || success.tpe <:< TypeTagClass.toTypeConstructor
            Select(Apply(Select(success, nme.in), List(Ident(nme.MIRROR_SHORT))), nme.tpe)
        }
      if (result != EmptyTree) return result
      state.reificationIsConcrete = false
    }

    EmptyTree
  }

  private def spliceAsManifest(tpe: Type): Tree = {
    def isSynthetic(manifest: Tree) = manifest exists (sub => sub.symbol != null && (sub.symbol == FullManifestModule || sub.symbol.owner == FullManifestModule))
    def searchForManifest(typer: analyzer.Typer): Tree =
      analyzer.inferImplicit(
        EmptyTree,
        appliedType(FullManifestClass.toTypeConstructor, List(tpe)),
        reportAmbiguous = false,
        isView = false,
        context = typer.context,
        saveAmbiguousDivergent = false,
        pos = defaultErrorPosition) match {
          case success if !success.tree.isEmpty && !isSynthetic(success.tree) =>
            val manifestInScope = success.tree
            // todo. write a test for this
            if (ReflectRuntimeUniverse == NoSymbol) CannotConvertManifestToTagWithoutScalaReflect(tpe, manifestInScope)
            val cm = typer.typed(Ident(ReflectRuntimeCurrentMirror))
            val internal = gen.mkAttributedSelect(gen.mkAttributedRef(ReflectRuntimeUniverse), UniverseInternal)
            val tagTree = gen.mkMethodCall(Select(internal, nme.manifestToTypeTag), List(tpe), List(cm, manifestInScope))
            Select(Apply(Select(tagTree, nme.in), List(Ident(nme.MIRROR_SHORT))), nme.tpe)
          case _ =>
            EmptyTree
        }
    val result = typer.silent(silentTyper => silentTyper.context.withMacrosDisabled(searchForManifest(silentTyper)))
    result match {
      case analyzer.SilentResultValue(result) => result
      case analyzer.SilentTypeError(_) => EmptyTree
    }
  }

  /** Reify a semi-concrete type member.
   *
   *  This is a VERY special case to deal with stuff like `typeOf[ru.Type]`.
   *  In that case `Type`, which is an abstract type member of scala.reflect.api.Universe, is not a free type.
   *  Why? Because we know its prefix, and it unambiguously determines the type.
   *
   *  Here is a different view on this question that supports this suggestion.
   *  Say, you reify a tree. Iff it doesn't contain free types, it can be successfully compiled and run.
   *  For example, if you reify `tpe.asInstanceOf[T]` taken from `def foo[T]`, then you won't be able to compile the result.
   *  Fair enough, you don't know the `T`, so the compiler will choke.
   *  This fact is captured by reification result having a free type T (this can be inspected by calling `tree.freeTypes`).
   *  Now imagine you reify the following tree: `tpe.asInstanceOf[ru.Type]`.
   *  To the contrast with the previous example, that's totally not a problem.
   *
   *  Okay, so we figured out that `ru.Type` is not a free type.
   *  However, in our reification framework, this type would be treated a free type.
   *  Why? Because `tpe.isSpliceable` will return true.
   *  Hence we intervene and handle this situation in a special way.
   *
   *  By the way, we cannot change the definition of `isSpliceable`, because class tags also depend on it.
   *  And, you know, class tags don't care whether we select a type member from a concrete instance or get it from scope (as with type parameters).
   *  The type itself still remains not concrete, in the sense that we don't know its erasure.
   *  I.e. we can compile the code that involves `ru.Type`, but we cannot serialize an instance of `ru.Type`.
   */
  private def reifySemiConcreteTypeMember(tpe: Type): Tree = tpe match {
    case tpe @ TypeRef(pre @ SingleType(prepre, presym), sym, args) if sym.isAbstractType && !sym.isExistential =>
      mirrorBuildCall(nme.TypeRef, reify(pre), mirrorBuildCall(nme.selectType, reify(sym.owner), reify(sym.name.toString)), reify(args))
  }

  /** Reify an annotated type, i.e. the one that makes us deal with AnnotationInfos */
  private def reifyAnnotatedType(tpe: AnnotatedType): Tree = {
    val AnnotatedType(anns, underlying) = tpe
    mirrorBuildCall(nme.AnnotatedType, mkList(anns map reifyAnnotationInfo), reify(underlying))
  }

  /** Reify a tough type, i.e. the one that leads to creation of auxiliary symbols */
  private def reifyToughType(tpe: Type): Tree = {
    if (reifyDebug) println("tough type: %s (%s)".format(tpe, tpe.kind))

    def reifyScope(scope: Scope): Tree = {
      scope foreach reifySymDef
      mirrorBuildCall(nme.newScopeWith, scope.toList map reify: _*)
    }

    tpe match {
      case tpe @ RefinedType(parents, decls) =>
        reifySymDef(tpe.typeSymbol)
        mirrorBuildCall(nme.RefinedType, reify(parents), reifyScope(decls), reify(tpe.typeSymbol))
      case tpe @ ExistentialType(tparams, underlying) =>
        tparams foreach reifySymDef
        reifyBuildCall(nme.ExistentialType, tparams, underlying)
      case tpe @ ClassInfoType(parents, decls, clazz) =>
        reifySymDef(clazz)
        mirrorBuildCall(nme.ClassInfoType, reify(parents), reifyScope(decls), reify(tpe.typeSymbol))
      case tpe @ MethodType(params, restpe) =>
        params foreach reifySymDef
        reifyBuildCall(nme.MethodType, params, restpe)
      case tpe @ PolyType(tparams, underlying) =>
        tparams foreach reifySymDef
        reifyBuildCall(nme.PolyType, tparams, underlying)
      case _ =>
        throw new Error("internal error: %s (%s) is not supported".format(tpe, tpe.kind))
    }
  }
}

Other Scala source code examples

Here is a short list of links related to this Scala GenTypes.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.