aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Trees.scala
blob: 26cb0a0ccb39849e6d24c96993e4a0e3d1e32a87 (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
package dotty.tools.dotc.core

import Types._, Names._, Flags._, Positions._

object Trees {

  abstract class Modifiers {
    val flags: FlagSet
  }

  class MissingType {
    type Type
  }

  val missing: MissingType =
    new MissingType {
      type Type = Types.Type
    }

  /** Trees take a parameter indicating what the type of their `tpe` field
   *  is. Two choices: `Types.Type` or `missing.Type`.
   *  Untyped trees have type `Tree[missing.Type]`. Because `missing.Type`
   *  is a completely abstract type, there's nothing one can do with it.
   *
   *  Tree typing uses a copy-on-write implementation:
   *
   *   - You can never observe a `tpe` which is `null` (throws an exception)
   *   - So when creating a typed tree with `withType` we can re-use
   *     the existing tree transparently, assigning its `tpe` field,
   *     provided it was `null` before.
   *   - It is impossible to embed untyped trees in typed ones.
   *   - It is possible to embed typed trees in untyped ones. In fact
   *     there is an implicit conversion from `Tree[Types.Type]` to
   *     `Tree[missing.Type]` which wraps the typed tree in a
   *     `TypedSplice` node.
   *   - Type checking an untyped tree will remove all embedded `TypedSplice`
   *     nodes.
   */
  abstract class Tree[T] {
    def pos: Position

    private var _tpe: T = _

    def tpe: T = {
      if (_tpe == null) throw new UnAssignedTypeException(this)
      _tpe
    }

    def withType(tpe: Type): Tree[Type] = {
      val tree =
        (if (_tpe == null ||
            (_tpe.asInstanceOf[AnyRef] eq tpe.asInstanceOf[AnyRef])) this
         else shallowCopy).asInstanceOf[Tree[Type]]
      tree._tpe = tpe
      tree
    }

    def shallowCopy: Tree[T] = clone.asInstanceOf[Tree[T]]

  }

  case class Ident[T](name: Name)(implicit val pos: Position) extends Tree[T]

  case class Select[T](qualifier: Tree[T], name: Name)(implicit val pos: Position) extends Tree[T]

  case class Apply[T](fun: Tree[T], arg: Tree[T])(implicit val pos: Position) extends Tree[T]

  case class Pair[T](left: Tree[T], right: Tree[T])(implicit val pos: Position) extends Tree[T]

  case class ValDef[T](mods: Modifiers, name: Name, rtpe: Tree[T], rhs: Tree[T])(implicit val pos: Position) extends Tree[T]

  case class TypeDef[T](mods: Modifiers, name: Name, rhs: Tree[T])(implicit val pos: Position) extends Tree[T]

  case class DefDef[T](mods: Modifiers, name: Name, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], rtpe: Tree[T], rhs: Tree[T])(implicit val pos: Position) extends Tree[T]

  case class TypedSplice(tree: Tree[Type]) extends Tree[missing.Type] {
    def pos = tree.pos
  }

  implicit def embedTyped(tree: Tree[Type]): Tree[missing.Type] = TypedSplice(tree)

  class UnAssignedTypeException[T](tree: Tree[T]) extends Exception {
    override def getMessage: String = s"type of $tree is not assigned"
  }

}