aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/dotc/core/Trees.scala
blob: 3a0c4efadc41a87ffded18db188f3ac14afb81f1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                             
                                                                                                   






                            
































                                                                             
                                             



                     
                                         

   
                                                                              
 
                                                                                                  
 
                                                                                                    
 
                                                                                               
 
                                                                                                                            
 
                                                                                                              
 
                                                                                                                                                                                        
 













                                                                                                              






                                                                                                                                                                        
                      

   
                                                                              




                                                                      





































                                                                                      
 
package dotty.tools.dotc.core

import Types._, Names._, Flags._, Positions._, Contexts._, Constants._, SymDenotations._, Symbols._

object Trees {

  abstract class Modifiers {
    val flags: FlagSet
  }

  /** 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 clone).asInstanceOf[Tree[Type]]
      tree._tpe = tpe
      tree
    }

    def withPosition(pos: Position) = ???
  }

  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], args: List[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 TypeTree[T](original: Tree[T] = EmptyTree[T])(implicit val pos: Position) extends Tree[T]

  case class EmptyTree[T]() extends Tree[T] {
    val pos = NoPosition
  }

  case class Literal[T](const: Constant)(implicit val pos: Position) extends Tree[T]

  case class New[T](tpt: Tree[T])(implicit val pos: Position) extends Tree[T]

  case class ArrayValue[T](elemtpt: Tree[T], elems: List[Tree[T]])(implicit val pos: Position) extends Tree[T]

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

  class ImplicitDefDef[T](mods: Modifiers, name: Name, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], rtpe: Tree[T], rhs: Tree[T])
    (implicit pos: Position) extends DefDef[T](mods, name, tparams, vparamss, rtpe, rhs) {
    override def copy[T](mods: Modifiers, name: Name, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], rtpe: Tree[T], rhs: Tree[T])(implicit pos: Position) =
      new ImplicitDefDef[T](mods, name, tparams, vparamss, rtpe, rhs)
  }

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

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

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

  type TypedTree = Tree[Type]
  type UntypedTree = Tree[Nothing]

  // this will probably to its own file at some point.
  class MakeTypedTree(implicit val ctx: Context) extends AnyVal {
    implicit def pos = NoPosition
    def Ident(tp: NamedType) =
      Trees.Ident(tp.name).withType(tp)
    def Select(pre: TypedTree, tp: NamedType) =
      Trees.Select(pre, tp.name).withType(tp)
    def Apply(fn: TypedTree, args: List[TypedTree]) = {
      val fntpe @ MethodType(pnames, ptypes) = fn.tpe
      assert(sameLength(ptypes, args))
      Trees.Apply(fn, args).withType(fntpe.instantiate(args map (_.tpe)))
    }
    def TypeTree(tp: Type) =
      Trees.TypeTree().withType(tp)
    def New(tp: Type): TypedTree =
      Trees.New(TypeTree(tp))
    def Literal(const: Constant) =
      Trees.Literal(const).withType(const.tpe)
    def ArrayValue(elemtpt: TypedTree, elems: List[TypedTree]) =
      Trees.ArrayValue(elemtpt, elems).withType(defn.ArrayType.appliedTo(elemtpt.tpe))
    def NamedArg[T](name: Name, arg: TypedTree) =
      Trees.NamedArg(name, arg).withType(arg.tpe)

    // ----------------------------------------------------------

    def New(tp: Type, args: List[TypedTree]): TypedTree =
      Apply(
        Select(
          New(tp),
          TermRef(tp.normalizedPrefix, tp.typeSymbol.primaryConstructor.asTerm)),
        args)
  }

  def makeTypedTree(implicit ctx: Context) = new MakeTypedTree()(ctx)

}