Type members

Abstract type declarations

Abstract type declarations are written using TYPEVAR(sym|"T"). Optionally, lower bounds and higher bounds can be specified:

import treehugger.forest._, definitions._, treehuggerDSL._

val tree = (TYPEVAR("T"): Tree)
// tree: Tree = TypeDef(
//   Modifiers(0L, TypeName(""), List()),
//   TypeName("T"),
//   List(),
//   EmptyTree
// )

treeToString(tree)
// res0: String = "type T"

val tree2 = (TYPEVAR("T") LOWER(IntClass): Tree)
// tree2: Tree = TypeDef(
//   Modifiers(0L, TypeName(""), List()),
//   TypeName("T"),
//   List(),
//   TypeTree()
// )

treeToString(tree2)
// res1: String = "type T >: Int"

object sym {
  val T = RootClass.newAliasType("T")
  val A = RootClass.newAliasType("A")
  val B = RootClass.newAliasType("B")
}

val tree3 = (TYPEVAR(sym.T) UPPER(ComparableClass TYPE_OF sym.T): Tree)
// tree3: Tree = TypeDef(
//   Modifiers(0L, TypeName(""), List()),
//   TypeName("T"),
//   List(),
//   TypeTree()
// )

treeToString(tree3)
// res2: String = "type T <: Comparable[T]"

or in general:

(TYPEVAR(sym|"T") [LOWER(lo|"C")] [UPPER(hi|"D")]).tree

where lo denotes an optional lower bound type and hi upper bound type.

Type alias definitions

Type alias definitions are written by appending := and right-hand side Type. The alias may accompany type parameters given by withTypeParams(TYPEVAR(...), ...):

val tree4 = TYPEVAR("IntList") := TYPE_LIST(IntClass)
// tree4: TypeDef = TypeDef(
//   Modifiers(0L, TypeName(""), List()),
//   TypeName("IntList"),
//   List(),
//   TypeTree()
// )

treeToString(tree4)
// res3: String = "type IntList = List[Int]"

val tree5 = TYPEVAR("Two") withTypeParams(TYPEVAR(sym.A)) := TYPE_TUPLE(sym.A, sym.A)
// tree5: TypeDef = TypeDef(
//   Modifiers(0L, TypeName(""), List()),
//   TypeName("Two"),
//   List(
//     TypeDef(
//       Modifiers(0L, TypeName(""), List()),
//       TypeName("A"),
//       List(),
//       EmptyTree
//     )
//   ),
//   TypeTree()
// )

treeToString(tree5)
// res4: String = "type Two[A] = (A, A)"

or in general:

TYPEVAR(sym|"T") [withTypeParams(TYPEVAR(typ1), ...)] := typ2

Variance annotations

Variance annotations for the type parameters are set using COVARIANT(...) and CONTRAVARIANT(...):

val A = RootClass.newTypeParameter("A")
// A: TypeSymbol = A

val tree6 = (TYPEVAR("M") withTypeParams(TYPEVAR(COVARIANT(A))): Tree)
// tree6: Tree = TypeDef(
//   Modifiers(0L, TypeName(""), List()),
//   TypeName("M"),
//   List(
//     TypeDef(
//       Modifiers(0L, TypeName(""), List()),
//       TypeName("A"),
//       List(),
//       EmptyTree
//     )
//   ),
//   EmptyTree
// )

val tree7 = (TYPEVAR("M") withTypeParams(TYPEVAR(CONTRAVARIANT(A))): Tree)
// tree7: Tree = TypeDef(
//   Modifiers(0L, TypeName(""), List()),
//   TypeName("M"),
//   List(
//     TypeDef(
//       Modifiers(0L, TypeName(""), List()),
//       TypeName("A"),
//       List(),
//       EmptyTree
//     )
//   ),
//   EmptyTree
// )

The above examples print as:

treeToString(tree6)
// res5: String = "type M[+A]"

treeToString(tree7)
// res6: String = "type M[-A]"