summaryrefslogtreecommitdiff
path: root/sources/scala/tools/nsc/ast/TreeGen.scala
blob: 425cf9eac8cc050357927b578f11d63dfcb10a13 (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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author  Martin Odersky
 */
// $Id$
package scala.tools.nsc.ast;

import scala.tools.nsc.util.Position;
import symtab.Flags._;

abstract class TreeGen {

  val global: Global;

  import global._;
  import definitions._;
  import posAssigner.atPos;

  /** Builds a reference to value whose type is given stable prefix.
   */
  def mkQualifier(tpe: Type): Tree = tpe match {
    case NoPrefix =>
      EmptyTree
    case ThisType(clazz) =>
      if (clazz.isRoot || clazz.isEmptyPackageClass) EmptyTree else This(clazz)
    case SingleType(pre, sym) =>
      if (sym.isThisSkolem) {
        mkQualifier(ThisType(sym.deSkolemize))
      } else {
        val qual = mkStableRef(pre, sym);
        qual.tpe match {
          case MethodType(List(), restpe) =>
            Apply(qual, List()) setType restpe
          case _ =>
            qual
        }
      }
    case TypeRef(pre, sym, args) =>
      assert(phase.erasedTypes);
      if (sym.isModuleClass && !sym.isRoot) {
        val qual = Select(mkQualifier(sym.owner.tpe), sym.sourceModule);
        qual.tpe match {
	  case MethodType(List(), restpe) =>
	    Apply(qual, List()) setType restpe
          case _ =>
            qual
        }
      } else This(sym)
  }

  /** Builds a reference to given symbol with given stable prefix. */
  def mkRef(pre: Type, sym: Symbol): Tree  = {
    val qual = mkQualifier(pre);
    if (qual == EmptyTree) Ident(sym) else Select(qual, sym)
  }

  /** Builds a reference to given symbol. */
  def mkRef(sym: Symbol): Tree =
    if (sym.owner.isClass) mkRef(sym.owner.thisType, sym) else Ident(sym);

  /** Replaces tree type with a stable type if possible */
  def stabilize(tree: Tree): Tree = tree match {
    case Ident(_) =>
      if (tree.symbol.isStable) tree.setType(singleType(tree.symbol.owner.thisType, tree.symbol))
      else tree
    case Select(qual, _) =>
      if (tree.symbol.isStable && qual.tpe.isStable) tree.setType(singleType(qual.tpe, tree.symbol))
      else tree
    case _ =>
      tree
  }

  /** Cast `tree' to type `pt' */
  def cast(tree: Tree, pt: Type): Tree = {
    if (settings.debug.value) log("casting " + tree + ":" + tree.tpe + " to " + pt);
    assert(!tree.tpe.isInstanceOf[MethodType], tree);
    typer.typed {
      atPos(tree.pos) {
	Apply(TypeApply(Select(tree, Object_asInstanceOf), List(TypeTree(pt))), List())
      }
    }
  }

  /** Builds a reference with stable type to given symbol */
  def mkStableRef(pre: Type, sym: Symbol): Tree  = stabilize(mkRef(pre, sym));
  def mkStableRef(sym: Symbol): Tree  = stabilize(mkRef(sym));

  def This(sym: Symbol): Tree =
    global.This(sym.name) setSymbol sym setType sym.thisType;

  def Ident(sym: Symbol): Tree = {
    assert(sym.isTerm);
    global.Ident(sym.name) setSymbol sym setType sym.tpe;
  }

  def Select(qual: Tree, sym: Symbol): Tree =
    if (qual.symbol != null &&
        (qual.symbol.name.toTermName == nme.ROOT ||
         qual.symbol.name.toTermName == nme.EMPTY_PACKAGE_NAME)) {
      this.Ident(sym)
    } else {
      assert(sym.isTerm);
      val result = global.Select(qual, sym.name) setSymbol sym;
      if (qual.tpe != null) result setType qual.tpe.memberType(sym);
      result
    }

  /** Builds an instance test with given value and type. */
  def mkIsInstanceOf(value: Tree, tpe: Type, erased: Boolean): Tree = {
    val sym =
      if(erased)
        definitions.Any_isInstanceOfErased
      else
        definitions.Any_isInstanceOf;
    Apply(
      TypeApply(
        Select(value, sym),
        List(TypeTree(tpe))),
      List())
  }

  def mkIsInstanceOf(value: Tree, tpe: Type): Tree = {
    mkIsInstanceOf(value, tpe, global.phase.erasedTypes);
  }

  /** Builds a cast with given value and type. */
  def mkAsInstanceOf(value: Tree, tpe: Type, erased: Boolean): Tree = {
    val sym =
      if(erased)
        definitions.Any_asInstanceOfErased
      else
        definitions.Any_asInstanceOf;

    Apply(
      TypeApply(
        Select(value, sym),
        List(TypeTree(tpe))),
      List())
  }

  def mkAsInstanceOf(value: Tree, tpe: Type): Tree = {
    mkAsInstanceOf(value, tpe, global.phase.erasedTypes);
  }


  /** Builds a list with given head and tail. */
  def mkNewCons(head: Tree, tail: Tree):  Tree =
    New(Apply(mkRef(definitions.ConsClass), List(head,tail)));

  /** Builds a list with given head and tail. */
  def mkNil: Tree =
    mkRef(definitions.NilModule);

  /** Builds a pair */
  def mkNewPair(left: Tree, right: Tree) =
    New(Apply(mkRef(definitions.TupleClass(2)), List(left,right)));

}