summaryrefslogtreecommitdiff
path: root/src/compiler/scala/reflect/reify/package.scala
blob: 35b3d9bf38bc0222d821182c9f355543834d55e2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package scala.reflect

import scala.tools.nsc.Global
import scala.reflect.makro.ReificationError
import scala.reflect.makro.UnexpectedReificationError

package object reify {
  private def mkReifier(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, reifee: Any, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): Reifier { val mirror: global.type } = {
    val typer1: typer.type = typer
    val prefix1: prefix.type = prefix
    val reifee1 = reifee
    val dontSpliceAtTopLevel1 = dontSpliceAtTopLevel
    val concrete1 = concrete

    new {
      val mirror: global.type = global
      val typer = typer1
      val prefix = prefix1
      val reifee = reifee1
      val dontSpliceAtTopLevel = dontSpliceAtTopLevel1
      val concrete = concrete1
    } with Reifier
  }

  def reifyTree(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, tree: global.Tree): global.Tree =
    mkReifier(global)(typer, prefix, tree, false, false).reified.asInstanceOf[global.Tree]

  def reifyType(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, tpe: global.Type, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): global.Tree =
    mkReifier(global)(typer, prefix, tpe, dontSpliceAtTopLevel, concrete).reified.asInstanceOf[global.Tree]

  def reifyRuntimeClass(global: Global)(typer0: global.analyzer.Typer, tpe: global.Type, concrete: Boolean = true): global.Tree = {
    import global._
    import definitions._
    import analyzer.enclosingMacroPosition

    def erasureTagInScope = typer0.context.withMacrosDisabled(typer0.resolveErasureTag(tpe, enclosingMacroPosition, concrete = concrete))
    def arrayTagInScope = typer0.context.withMacrosDisabled(typer0.resolveArrayTag(tpe, enclosingMacroPosition))
    val inScope = (erasureTagInScope, arrayTagInScope)

    inScope match {
      case (success, _) if !success.isEmpty =>
        Select(success, nme.runtimeClass)
      case (_, success) if !success.isEmpty =>
        gen.mkMethodCall(arrayElementClassMethod, List(success))
      case _ =>
        tpe.normalize match {
          case TypeRef(_, ArrayClass, componentTpe :: Nil) =>
            val componentRuntimeClass = reifyRuntimeClass(global)(typer0, componentTpe, concrete)
            gen.mkMethodCall(arrayClassMethod, List(componentRuntimeClass))
          case _ =>
            if (tpe.isSpliceable && concrete)
              throw new ReificationError(enclosingMacroPosition, "tpe %s is an unresolved spliceable type".format(tpe))
            var erasure = tpe.erasure
            if (tpe.typeSymbol.isDerivedValueClass && global.phase.id < global.currentRun.erasurePhase.id) erasure = tpe
            gen.mkNullaryCall(Predef_classOf, List(erasure))
        }
    }
  }
}