scala.quasiquotes.ReificationSupport.scala Maven / Gradle / Ivy
package scala.quasiquotes
import scala.reflect.internal.Flags._
import scala.reflect.internal.util._
import scala.reflect.internal.SymbolTable
abstract class ReificationSupport extends SymbolTableCompat { self =>
val global: SymbolTable
import global.{definitions => _, nme => _, tpnme => _, lowerTermNames => _, copyValDef => _, deriveTemplate => _, _}
import symbolTable._
import definitions._
def selectType(owner: Symbol, name: String): TypeSymbol =
select(owner, newTypeName(name)).asType
def selectTerm(owner: Symbol, name: String): TermSymbol = {
val result = select(owner, newTermName(name)).asTerm
if (result.isOverloaded) result.suchThat(!_.isMethod).asTerm
else result
}
protected def select(owner: Symbol, name: Name): Symbol = {
val result = owner.info declaration name
if (result ne NoSymbol) result
else {
val mirror = mirrorThatLoaded(owner)
val m_missingHook = mirror.getClass().getMethod("missingHook")
val result = m_missingHook.invoke(mirror, owner, name).asInstanceOf[Symbol]
result orElse {
throw new ScalaReflectionException("%s %s in %s not found".format(if (name.isTermName) "term" else "type", name, owner.fullName))
}
}
}
def selectOverloadedMethod(owner: Symbol, name: String, index: Int): MethodSymbol = {
val sym = owner.info.declaration(newTermName(name))
val alternatives = sym match {
case sym if sym.isTerm => (sym.asTerm: scala.reflect.api.Symbols#TermSymbol).alternatives.asInstanceOf[List[Symbol]]
case _ => List(sym)
}
val result = alternatives(index)
if (result ne NoSymbol) result.asMethod
else throw new ScalaReflectionException("overloaded method %s #%d in %s not found".format(name, index, owner.fullName))
}
def newFreeTerm(name: String, value: => Any, flags: Long = 0L, origin: String = null): FreeTermSymbol =
newFreeTermSymbol(newTermName(name), value, flags, origin)
def newFreeType(name: String, flags: Long = 0L, origin: String = null): FreeTypeSymbol =
newFreeTypeSymbol(newTypeName(name), flags, origin)
def newNestedSymbol(owner: Symbol, name: Name, pos: Position, flags: Long, isClass: Boolean): Symbol =
owner.newNestedSymbol(name, pos, flags, isClass)
def newScopeWith(elems: Symbol*): Scope =
global.newScopeWith(elems: _*)
def setAnnotations[S <: Symbol](sym: S, annots: List[AnnotationInfo]): S =
sym.my_setAnnotations(annots).asInstanceOf[S]
def setInfo[S <: Symbol](sym: S, tpe: Type): S =
sym.my_setInfo(tpe).asInstanceOf[S]
def mkThis(sym: Symbol): Tree = global.This(sym)
def mkSelect(qualifier: Tree, sym: Symbol): Select = global.Select(qualifier, sym)
def mkIdent(sym: Symbol): Ident = global.Ident(sym)
def mkTypeTree(tp: Type): TypeTree = global.TypeTree(tp)
def ThisType(sym: Symbol): Type = global.ThisType(sym)
def SingleType(pre: Type, sym: Symbol): Type = global.SingleType(pre, sym)
def SuperType(thistpe: Type, supertpe: Type): Type = global.SuperType(thistpe, supertpe)
def ConstantType(value: Constant): ConstantType = global.ConstantType(value)
def TypeRef(pre: Type, sym: Symbol, args: List[Type]): Type = global.TypeRef(pre, sym, args)
def RefinedType(parents: List[Type], decls: Scope, typeSymbol: Symbol): RefinedType = global.RefinedType(parents, decls, typeSymbol)
def ClassInfoType(parents: List[Type], decls: Scope, typeSymbol: Symbol): ClassInfoType = global.ClassInfoType(parents, decls, typeSymbol)
def MethodType(params: List[Symbol], resultType: Type): MethodType = global.MethodType(params, resultType)
def NullaryMethodType(resultType: Type): NullaryMethodType = global.NullaryMethodType(resultType)
def PolyType(typeParams: List[Symbol], resultType: Type): PolyType = global.PolyType(typeParams, resultType)
def ExistentialType(quantified: List[Symbol], underlying: Type): ExistentialType = global.ExistentialType(quantified, underlying)
def AnnotatedType(annotations: List[Annotation], underlying: Type, selfSym: Symbol): AnnotatedType = global.AnnotatedType(annotations, underlying, selfSym)
def TypeBounds(lo: Type, hi: Type): TypeBounds = global.TypeBounds(lo, hi)
def BoundedWildcardType(bounds: TypeBounds): BoundedWildcardType = global.BoundedWildcardType(bounds)
def thisPrefix(sym: Symbol): Type = sym.my_thisPrefix
def setType[T <: Tree](tree: T, tpe: Type): T = { tree.setType(tpe); tree }
def setSymbol[T <: Tree](tree: T, sym: Symbol): T = { tree.setSymbol(sym); tree }
def toStats(tree: Tree): List[Tree] = tree match {
case EmptyTree => Nil
case SyntacticBlock(stats) => stats
case _ => throw new IllegalArgumentException(s"can't flatten $tree")
}
def mkAnnotation(tree: Tree): Tree = tree match {
case SyntacticNew(Nil, SyntacticApplied(SyntacticAppliedType(_, _), _) :: Nil, emptyValDef, Nil) =>
tree
case _ =>
throw new IllegalArgumentException(s"Tree ${showRaw(tree)} isn't a correct representation of annotation." +
"""Consider reformatting it into a q"new $name[..$targs](...$argss)" shape""")
}
def mkAnnotation(trees: List[Tree]): List[Tree] = trees.map(mkAnnotation)
def mkParam(argss: List[List[Tree]], extraFlags: FlagSet = NoFlags, excludeFlags: FlagSet = DEFERRED): List[List[ValDef]] =
argss.map { args => args.map { mkParam(_, extraFlags, excludeFlags) } }
def mkParam(tree: Tree, extraFlags: FlagSet, excludeFlags: FlagSet): ValDef = tree match {
case Typed(Ident(name: TermName), tpt) =>
mkParam(ValDef(NoMods, name, tpt, EmptyTree), extraFlags, excludeFlags)
case vd: ValDef =>
var newmods = vd.mods my_& (~excludeFlags)
if (vd.rhs.nonEmpty) newmods = newmods my_| DEFAULTPARAM
copyValDef(vd)(mods = newmods my_| extraFlags)
case _ =>
throw new IllegalArgumentException(s"$tree is not valid represenation of a parameter, " +
"""consider reformatting it into q"val $name: $T = $default" shape""")
}
def mkImplicitParam(args: List[Tree]): List[ValDef] = args.map(mkImplicitParam)
def mkImplicitParam(tree: Tree): ValDef = mkParam(tree, IMPLICIT | PARAM, NoFlags)
def mkTparams(tparams: List[Tree]): List[TypeDef] =
tparams.map {
case td: TypeDef => copyTypeDef(td)(mods = (td.mods my_| PARAM) my_& (~DEFERRED))
case other => throw new IllegalArgumentException(s"can't splice $other as type parameter")
}
def mkRefineStat(stat: Tree): Tree = {
stat match {
case dd: DefDef => require(dd.rhs.isEmpty, "can't use DefDef with non-empty body as refine stat")
case vd: ValDef => require(vd.rhs.isEmpty, "can't use ValDef with non-empty rhs as refine stat")
case td: TypeDef =>
case _ => throw new IllegalArgumentException(s"not legal refine stat: $stat")
}
stat
}
def mkRefineStat(stats: List[Tree]): List[Tree] = stats.map(mkRefineStat)
def mkPackageStat(stat: Tree): Tree = {
stat match {
case cd: ClassDef =>
case md: ModuleDef =>
case pd: PackageDef =>
case _ => throw new IllegalArgumentException(s"not legal package stat: $stat")
}
stat
}
def mkPackageStat(stats: List[Tree]): List[Tree] = stats.map(mkPackageStat)
object ScalaDot {
def apply(name: Name): Tree = gen.scalaDot(name)
def unapply(tree: Tree): Option[Name] = tree match {
case Select(id @ Ident(nme.scala_), name) if id.symbol == ScalaPackage => Some(name)
case _ => None
}
}
def mkEarlyDef(defn: Tree): Tree = defn match {
case vdef @ ValDef(mods, _, _, _) if !mods.my_isDeferred =>
copyValDef(vdef)(mods = mods my_| PRESUPER)
case tdef @ TypeDef(mods, _, _, _) =>
copyTypeDef(tdef)(mods = mods my_| PRESUPER)
case _ =>
throw new IllegalArgumentException(s"not legal early def: $defn")
}
def mkEarlyDef(defns: List[Tree]): List[Tree] = defns.map(mkEarlyDef)
def mkRefTree(qual: Tree, sym: Symbol): RefTree = global.RefTree(qual, sym.name) setSymbol sym
def freshTermName(prefix: String = nme.FRESH_TERM_NAME_PREFIX): TermName = global.freshTermName(prefix)
def freshTypeName(prefix: String): TypeName = global.freshTypeName(prefix)
protected implicit def fresh: FreshNameCreator = global.currentFreshNameCreator
object ImplicitParams {
def apply(paramss: List[List[Tree]], implparams: List[Tree]): List[List[Tree]] =
if (implparams.nonEmpty) paramss :+ mkImplicitParam(implparams) else paramss
def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])] = vparamss match {
case init :+ (last @ (initlast :: _)) if initlast.mods.my_isImplicit => Some((init, last))
case _ => Some((vparamss, Nil))
}
}
object FlagsRepr {
def apply(bits: Long): FlagSet = bits
def unapply(flags: Long): Some[Long] = Some(flags)
}
/** Construct/deconstruct type application term trees.
* Treats other term trees as zero-argument type applications.
*/
object SyntacticTypeApplied {
def apply(tree: Tree, targs: List[Tree]): Tree =
if (targs.isEmpty) tree
else if (tree.isTerm) TypeApply(tree, targs)
else throw new IllegalArgumentException(s"can't apply type arguments to $tree")
def unapply(tree: Tree): Option[(Tree, List[Tree])] = tree match {
case TypeApply(fun, targs) => Some((fun, targs))
case _ if tree.isTerm => Some((tree, Nil))
case _ => None
}
}
/** Construct/deconstruct applied type trees.
* Treats other types as zero-arity applied types.
*/
object SyntacticAppliedType {
def apply(tree: Tree, targs: List[Tree]): Tree =
if (targs.isEmpty) tree
else if (tree.isType) AppliedTypeTree(tree, targs)
else throw new IllegalArgumentException(s"can't create applied type from non-type $tree")
def unapply(tree: Tree): Option[(Tree, List[Tree])] = tree match {
case MaybeTypeTreeOriginal(AppliedTypeTree(tpe, targs)) => Some((tpe, targs))
case _ if tree.isType => Some((tree, Nil))
case _ => None
}
}
object SyntacticApplied {
def apply(tree: Tree, argss: List[List[Tree]]): Tree =
argss.foldLeft(tree) { (f, args) => Apply(f, args.map(treeInfo.assignmentToMaybeNamedArg)) }
def unapply(tree: Tree): Some[(Tree, List[List[Tree]])] = tree match {
case UnApply(treeInfo.Unapplied(Select(fun, nme.unapply)), pats) =>
Some((fun, pats :: Nil))
case treeInfo.Applied(fun, targs, argss) =>
fun match {
case Select(_: New, nme.CONSTRUCTOR) =>
Some((tree, Nil))
case _ =>
val callee =
if (fun.isTerm) SyntacticTypeApplied(fun, targs)
else SyntacticAppliedType(fun, targs)
Some((callee, argss))
}
}
}
// recover constructor contents generated by gen.mkTemplate
private object UnCtor {
def unapply(tree: Tree): Option[(Modifiers, List[List[ValDef]], List[List[Tree]], List[Tree])] = tree match {
// NOTE: should be SyntacticBlock(lvdefs :+ _), but have to work around because of emulation that we have to do for SyntacticBlock
// read more about the workaround in comments for SyntacticBlock
case DefDef(mods, nme.MIXIN_CONSTRUCTOR, _, _, _, SyntacticBlock(lvdefs)) =>
Some((mods my_| Flag.TRAIT, Nil, Nil, lvdefs))
case DefDef(mods, nme.CONSTRUCTOR, Nil, vparamss, _, SyntacticBlock(lvdefs :+ SyntacticApplied(_, argss) :+ _)) =>
Some((mods, vparamss, argss, lvdefs))
case _ => None
}
}
// undo gen.mkTemplate
private object UnMkTemplate {
def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = {
val Template(parents0, selfdef, _) = templ
val tbody = treeInfo.untypecheckedTemplBody(templ)
def result(ctorMods: Modifiers, vparamss: List[List[ValDef]], edefs: List[Tree], parents: List[Tree], body: List[Tree]) =
Some((parents, selfdef, ctorMods, vparamss, edefs, body))
def indexOfCtor(trees: List[Tree]) =
trees.indexWhere { case UnCtor(_, _, _, _) => true ; case _ => false }
if (tbody forall treeInfo.isInterfaceMember)
result(NoMods my_| Flag.TRAIT, Nil, Nil, parents0, tbody)
else if (indexOfCtor(tbody) == -1)
None
else {
val (rawEdefs, rest) = tbody.span(treeInfo.isEarlyDef)
val (gvdefs, etdefs) = rawEdefs.partition(treeInfo.isEarlyValDef)
val (fieldDefs, UnCtor(ctorMods, ctorVparamss, argss, lvdefs) :: body) = rest.splitAt(indexOfCtor(rest))
val parents = parents0 match {
case head :: tail =>
if (argss == List(Nil)) parents0
else SyntacticApplied(head, argss) :: tail
case Nil =>
Nil
}
val evdefs = gvdefs.zip(lvdefs).map {
case (gvdef @ ValDef(_, _, tpt: TypeTree, _), ValDef(_, _, _, rhs)) =>
copyValDef(gvdef)(tpt = tpt.original, rhs = rhs)
case (gvdef @ ValDef(_, _, tpt, _), ValDef(_, _, _, rhs)) =>
copyValDef(gvdef)(tpt = tpt, rhs = rhs)
}
val edefs = evdefs ::: etdefs
if (ctorMods.my_isTrait)
result(ctorMods, Nil, edefs, parents, body)
else {
// undo conversion from (implicit ... ) to ()(implicit ... ) when its the only parameter section
val vparamssRestoredImplicits = ctorVparamss match {
case Nil :: (tail @ ((head :: _) :: _)) if head.mods.hasFlag(IMPLICIT) => tail
case other => other
}
// undo flag modifications by mergeing flag info from constructor args and fieldDefs
val modsMap = fieldDefs.map { case ValDef(mods, name, _, _) => name -> mods }.toMap
def ctorArgsCorrespondToFields = vparamssRestoredImplicits.flatten.forall { vd => modsMap.contains(vd.name) }
if (!ctorArgsCorrespondToFields) None
else {
val vparamss = scala.quasiquotes.Collections.mmap(vparamssRestoredImplicits) { vd =>
val originalMods = modsMap(vd.name) my_| (vd.mods.flags & DEFAULTPARAM)
atPos(vd.pos)(ValDef(originalMods, vd.name, vd.tpt, vd.rhs))
}
result(ctorMods, vparamss, edefs, parents, body)
}
}
}
}
}
protected def mkSelfType(tree: Tree) = tree match {
case vd: ValDef =>
require(vd.rhs.isEmpty, "self types must have empty right hand side")
copyValDef(vd)(mods = (vd.mods my_| PRIVATE) my_& (~DEFERRED))
case _ =>
throw new IllegalArgumentException(s"$tree is not a valid representation of self type, " +
"""consider reformatting into q"val $self: $T" shape""")
}
object SyntacticClassDef {
def apply(mods: Modifiers, name: TypeName, tparams: List[Tree],
constrMods: Modifiers, vparamss: List[List[Tree]],
earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = {
val extraFlags = PARAMACCESSOR | (if (mods.my_isCase) CASEACCESSOR else 0L)
val vparamss0 = mkParam(vparamss, extraFlags, excludeFlags = DEFERRED | PARAM)
val tparams0 = mkTparams(tparams)
val parents0 = gen.mkParents(mods,
if (mods.my_isCase) parents.filter {
case ScalaDot(tpnme.Product | tpnme.Serializable | tpnme.AnyRef) => false
case _ => true
} else parents
)
val body0 = earlyDefs ::: body
val selfType0 = mkSelfType(selfType)
val templ = gen.mkTemplate(parents0, selfType0, constrMods, vparamss0, body0)
gen.mkClassDef(mods, name, tparams0, templ)
}
def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]],
List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
case ClassDef(mods, name, tparams, UnMkTemplate(parents, selfType, ctorMods, vparamss, earlyDefs, body))
if !ctorMods.my_isTrait && !ctorMods.hasFlag(JAVA) =>
Some((mods, name, tparams, ctorMods, vparamss, earlyDefs, parents, selfType, body))
case _ =>
None
}
}
object SyntacticTraitDef {
def apply(mods: Modifiers, name: TypeName, tparams: List[Tree], earlyDefs: List[Tree],
parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = {
val mods0 = mods my_| TRAIT my_| ABSTRACT
val templ = gen.mkTemplate(parents, mkSelfType(selfType), Modifiers(TRAIT), Nil, earlyDefs ::: body)
gen.mkClassDef(mods0, name, mkTparams(tparams), templ)
}
def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef],
List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
case ClassDef(mods, name, tparams, UnMkTemplate(parents, selfType, ctorMods, vparamss, earlyDefs, body))
if mods.my_isTrait =>
Some((mods, name, tparams, earlyDefs, parents, selfType, body))
case _ => None
}
}
object SyntacticObjectDef {
def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree],
parents: List[Tree], selfType: Tree, body: List[Tree]): ModuleDef =
ModuleDef(mods, name, gen.mkTemplate(parents, mkSelfType(selfType), NoMods, Nil, earlyDefs ::: body))
def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
case ModuleDef(mods, name, UnMkTemplate(parents, selfType, _, _, earlyDefs, body)) =>
Some((mods, name, earlyDefs, parents, selfType, body))
case _ =>
None
}
}
object SyntacticPackageObjectDef {
def apply(name: TermName, earlyDefs: List[Tree],
parents: List[Tree], selfType: Tree, body: List[Tree]): PackageDef =
gen.mkPackageObject(SyntacticObjectDef(NoMods, name, earlyDefs, parents, selfType, body))
def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
case PackageDef(Ident(name: TermName), List(SyntacticObjectDef(NoMods, nme.PACKAGEkw, earlyDefs, parents, selfType, body))) =>
Some((name, earlyDefs, parents, selfType, body))
case _ =>
None
}
}
// match references to `scala.$name`
protected class ScalaMemberRef(symbols: Seq[Symbol]) {
def result(name: Name): Option[Symbol] =
symbols.collect { case sym if sym.name == name => sym }.headOption
def unapply(tree: Tree): Option[Symbol] = tree match {
case id @ Ident(name) if symbols.contains(id.symbol) && name == id.symbol.name =>
Some(id.symbol)
case Select(scalapkg @ Ident(nme.scala_), name) if scalapkg.symbol == ScalaPackage =>
result(name)
case Select(Select(Ident(nme.ROOTPKG), nme.scala_), name) =>
result(name)
case _ => None
}
}
protected object TupleClassRef extends ScalaMemberRef(TupleClass.seq)
protected object TupleCompanionRef extends ScalaMemberRef(TupleClass.seq.map { _.companionModule })
protected object UnitClassRef extends ScalaMemberRef(Seq(UnitClass))
protected object FunctionClassRef extends ScalaMemberRef(FunctionClass.seq)
object SyntacticTuple {
def apply(args: List[Tree]): Tree = {
require(args.isEmpty || TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported")
gen.mkTuple(args)
}
def unapply(tree: Tree): Option[List[Tree]] = tree match {
case Literal(Constant(())) =>
Some(Nil)
case Apply(MaybeTypeTreeOriginal(SyntacticTypeApplied(MaybeSelectApply(TupleCompanionRef(sym)), targs)), args)
if sym == TupleClass(args.length).companionModule
&& (targs.isEmpty || targs.length == args.length) =>
Some(args)
case _ if tree.isTerm =>
Some(tree :: Nil)
case _ =>
None
}
}
object SyntacticTupleType {
def apply(args: List[Tree]): Tree = {
require(args.isEmpty || TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported")
gen.mkTupleType(args)
}
def unapply(tree: Tree): Option[List[Tree]] = tree match {
case MaybeTypeTreeOriginal(UnitClassRef(_)) =>
Some(Nil)
case MaybeTypeTreeOriginal(AppliedTypeTree(TupleClassRef(sym), args))
if sym == TupleClass(args.length) =>
Some(args)
case _ if tree.isType =>
Some(tree :: Nil)
case _ =>
None
}
}
object SyntacticFunctionType {
def apply(argtpes: List[Tree], restpe: Tree): Tree = {
require(FunctionClass(argtpes.length).exists, s"Function types with ${argtpes.length} arity aren't supported")
gen.mkFunctionTypeTree(argtpes, restpe)
}
def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match {
case MaybeTypeTreeOriginal(AppliedTypeTree(FunctionClassRef(sym), args @ (argtpes :+ restpe)))
if sym == FunctionClass(args.length - 1) =>
Some((argtpes, restpe))
case _ => None
}
}
object SyntheticUnit {
def unapply(tree: Tree): Boolean = tree match {
case Literal(Constant(())) if tree.hasAttachment[SyntheticUnitAttachment.type] => true
case _ => false
}
}
/** Syntactic combinator that abstracts over Block tree.
*
* Apart from providing a more straightforward api that exposes
* block as a list of elements rather than (stats, expr) pair
* it also:
*
* 1. Strips trailing synthetic units which are inserted by the
* compiler if the block ends with a definition rather
* than an expression or is empty.
*
* 2. Matches non-block term trees and recognizes them as
* single-element blocks for sake of consistency with
* compiler's default to treat single-element blocks with
* expressions as just expressions. The only exception is q""
* which is not considered to be a block.
*/
object SyntacticBlock {
def apply(stats: List[Tree]): Tree = gen.mkBlock(stats)
def unapply(tree: Tree): Option[List[Tree]] = tree match {
// NOTE: these clauses are here just because vanilla 2.10.x parser doesn't support SyntheticUnit
// therefore we have to emulate by dropping all units that conclude a block coming right after a definition
// ===== start of emulation block ====
// if you remove this clause, change UnCtor.unapply for mixin constructors
case bl @ global.Block(stats @ (_ :+ (_: DefTree)), Literal(Constant(()))) => Some(treeInfo.untypecheckedBlockBody(bl))
// ===== end of emulation block ====
case bl @ global.Block(stats, SyntheticUnit()) => Some(treeInfo.untypecheckedBlockBody(bl))
case bl @ global.Block(stats, expr) => Some(treeInfo.untypecheckedBlockBody(bl) :+ expr)
case SyntheticUnit() => Some(Nil)
case _ if tree.isTerm && tree.nonEmpty => Some(tree :: Nil)
case _ => None
}
}
object SyntacticFunction {
def apply(params: List[Tree], body: Tree): Function = {
val params0 :: Nil = mkParam(params :: Nil, PARAM)
require(params0.forall { _.rhs.isEmpty }, "anonymous functions don't support parameters with default values")
Function(params0, body)
}
def unapply(tree: Function): Option[(List[ValDef], Tree)] = Function.unapply(tree)
}
object SyntacticNew {
def apply(earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): Tree =
gen.mkNew(parents, mkSelfType(selfType), earlyDefs ::: body, NoPosition, NoPosition)
def unapply(tree: Tree): Option[(List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
case treeInfo.Applied(Select(New(SyntacticAppliedType(ident, targs)), nme.CONSTRUCTOR), Nil, List(Nil)) =>
Some((Nil, SyntacticAppliedType(ident, targs) :: Nil, global.asInstanceOf[scala.reflect.api.Universe].emptyValDef.asInstanceOf[global.ValDef], Nil))
case treeInfo.Applied(Select(New(SyntacticAppliedType(ident, targs)), nme.CONSTRUCTOR), Nil, argss) =>
Some((Nil, SyntacticApplied(SyntacticAppliedType(ident, targs), argss) :: Nil, global.asInstanceOf[scala.reflect.api.Universe].emptyValDef.asInstanceOf[global.ValDef], Nil))
case SyntacticBlock(SyntacticClassDef(_, tpnme.ANON_CLASS_NAME, Nil, _, ListOfNil, earlyDefs, parents, selfType, body) ::
Apply(Select(New(Ident(tpnme.ANON_CLASS_NAME)), nme.CONSTRUCTOR), Nil) :: Nil) =>
Some((earlyDefs, parents, selfType, body))
case _ =>
None
}
}
object SyntacticDefDef {
def apply(mods: Modifiers, name: TermName, tparams: List[Tree],
vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef = {
val tparams0 = mkTparams(tparams)
val vparamss0 = mkParam(vparamss, PARAM)
val rhs0 = {
if (name != nme.CONSTRUCTOR) rhs
else rhs match {
case Block(_, _) => rhs
case _ => Block(List(rhs), gen.mkSyntheticUnit)
}
}
DefDef(mods, name, tparams0, vparamss0, tpt, rhs0)
}
def unapply(tree: Tree): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)] = tree match {
case DefDef(mods, nme.CONSTRUCTOR, tparams, vparamss, tpt, Block(List(expr), Literal(Constant(())))) =>
Some((mods, nme.CONSTRUCTOR, tparams, vparamss, tpt, expr))
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
Some((mods, name.toTermName, tparams, vparamss, tpt, rhs))
case _ => None
}
}
protected class SyntacticValDefBase(isMutable: Boolean) {
def modifiers(mods: Modifiers): Modifiers = if (isMutable) mods my_| MUTABLE else mods
def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree): ValDef = ValDef(modifiers(mods), name, tpt, rhs)
def unapply(tree: Tree): Option[(Modifiers, TermName, Tree, Tree)] = tree match {
case ValDef(mods, name, tpt, rhs) if mods.hasFlag(MUTABLE) == isMutable =>
Some((mods, name, tpt, rhs))
case _ =>
None
}
}
object SyntacticValDef extends SyntacticValDefBase(isMutable = false)
object SyntacticVarDef extends SyntacticValDefBase(isMutable = true)
object SyntacticAssign {
def apply(lhs: Tree, rhs: Tree): Tree = gen.mkAssign(lhs, rhs)
def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
case Assign(lhs, rhs) => Some((lhs, rhs))
case AssignOrNamedArg(lhs, rhs) => Some((lhs, rhs))
case Apply(Select(fn, nme.update), args :+ rhs) => Some((atPos(fn.pos)(Apply(fn, args)), rhs))
case _ => None
}
}
// def UnliftListElementwise[T](unliftable: Unliftable[T]) = new UnliftListElementwise[T] {
// def unapply(lst: List[Tree]): Option[List[T]] = {
// val unlifted = lst.flatMap { unliftable.unapply(_) }
// if (unlifted.length == lst.length) Some(unlifted) else None
// }
// }
// def UnliftListOfListsElementwise[T](unliftable: Unliftable[T]) = new UnliftListOfListsElementwise[T] {
// def unapply(lst: List[List[Tree]]): Option[List[List[T]]] = {
// val unlifted = lst.map { l => l.flatMap { unliftable.unapply(_) } }
// if (unlifted.flatten.length == lst.flatten.length) Some(unlifted) else None
// }
// }
object SyntacticValFrom {
def apply(pat: Tree, rhs: Tree): Tree = gen.ValFrom(pat, gen.mkCheckIfRefutable(pat, rhs))
def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
case gen.ValFrom(pat, UnCheckIfRefutable(pat1, rhs1)) if pat.equalsStructure(pat1) =>
Some((pat, rhs1))
case gen.ValFrom(pat, rhs) =>
Some((pat, rhs))
case _ => None
}
}
object SyntacticValEq {
def apply(pat: Tree, rhs: Tree): Tree = gen.ValEq(pat, rhs)
def unapply(tree: Tree): Option[(Tree, Tree)] = gen.ValEq.unapply(tree)
}
object SyntacticFilter {
def apply(tree: Tree): Tree = gen.Filter(tree)
def unapply(tree: Tree): Option[Tree] = gen.Filter.unapply(tree)
}
// If a tree in type position isn't provided by the user (e.g. `tpt` fields of
// `ValDef` and `DefDef`, function params etc), then it's going to be parsed as
// TypeTree with empty original and empty tpe. This extractor matches such trees
// so that one can write q"val x = 2" to match typecheck(q"val x = 2"). Note that
// TypeTree() is the only possible representation for empty trees in type positions.
// We used to sometimes receive EmptyTree in such cases, but not anymore.
object SyntacticEmptyTypeTree {
def apply(): TypeTree = global.TypeTree()
def unapply(tt: TypeTree): Boolean = tt.original == null || tt.original.isEmpty
}
// match a sequence of desugared `val $pat = $value`
protected object UnPatSeq {
def unapply(trees: List[Tree]): Option[List[(Tree, Tree)]] = {
val imploded = implodePatDefs(trees)
val patvalues = imploded.flatMap {
case SyntacticPatDef(_, pat, EmptyTree, rhs) => Some((pat, rhs))
case ValDef(_, name, SyntacticEmptyTypeTree(), rhs) => Some((Bind(name, global.Ident(nme.WILDCARD)), rhs))
case ValDef(_, name, tpt, rhs) => Some((Bind(name, Typed(global.Ident(nme.WILDCARD), tpt)), rhs))
case _ => None
}
if (patvalues.length == imploded.length) Some(patvalues) else None
}
}
// implode multiple-statement desugaring of pattern definitions
// into single-statement valdefs with nme.QUASIQUOTE_PAT_DEF name
object implodePatDefs extends Transformer {
override def transform(tree: Tree) = tree match {
case templ: Template => deriveTemplate(templ)(transformStats)
case block: Block =>
val Block(init, last) = block
Block(transformStats(init), transform(last)).copyAttrs(block)
case ValDef(mods, name1, SyntacticEmptyTypeTree(), Match(MaybeTyped(MaybeUnchecked(value), tpt), CaseDef(pat, EmptyTree, Ident(name2)) :: Nil))
if name1 == name2 =>
ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value))
case _ =>
super.transform(tree)
}
def transformStats(trees: List[Tree]): List[Tree] = trees match {
case Nil => Nil
case ValDef(mods, _, SyntacticEmptyTypeTree(), Match(MaybeTyped(MaybeUnchecked(value), tpt), CaseDef(pat, EmptyTree, SyntacticTuple(ids)) :: Nil)) :: tail
if mods.hasFlag(SYNTHETIC) && mods.hasFlag(ARTIFACT) =>
ids match {
case Nil =>
ValDef(NoMods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value)) :: transformStats(tail)
case _ =>
val mods = tail.take(1).head.asInstanceOf[ValDef].mods
ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value)) :: transformStats(tail.drop(ids.length))
}
case other :: tail =>
transform(other) :: transformStats(tail)
}
def apply(tree: Tree) = transform(tree)
def apply(trees: List[Tree]) = transformStats(trees)
}
object SyntacticPatDef {
def apply(mods: Modifiers, pat: Tree, tpt: Tree, rhs: Tree): List[ValDef] = tpt match {
case SyntacticEmptyTypeTree() => gen.mkPatDef(mods, pat, rhs)
case _ => gen.mkPatDef(mods, Typed(pat, tpt), rhs)
}
def unapply(tree: Tree): Option[(Modifiers, Tree, Tree, Tree)] = tree match {
case ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), rhs) => Some((mods, pat, tpt, rhs))
case _ => None
}
}
// match a sequence of desugared `val $pat = $value` with a tuple in the end
protected object UnPatSeqWithRes {
def unapply(tree: Tree): Option[(List[(Tree, Tree)], List[Tree])] = tree match {
case SyntacticBlock(UnPatSeq(trees) :+ SyntacticTuple(elems)) => Some((trees, elems))
case _ => None
}
}
// undo gen.mkSyntheticParam
protected object UnSyntheticParam {
def unapply(tree: Tree): Option[TermName] = tree match {
case ValDef(mods, name, _, EmptyTree)
if mods.hasFlag(SYNTHETIC) && mods.hasFlag(PARAM) =>
Some(name)
case _ => None
}
}
// undo gen.mkVisitor
protected object UnVisitor {
def unapply(tree: Tree): Option[(TermName, List[CaseDef])] = tree match {
case Function(UnSyntheticParam(x1) :: Nil, Match(MaybeUnchecked(Ident(x2)), cases))
if x1 == x2 =>
Some((x1, cases))
case _ => None
}
}
// undo gen.mkFor:makeClosure
protected object UnClosure {
private val PARAM = 1 << 13
def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
case Function(ValDef(Modifiers(FlagsRepr(PARAM), _, _), name, tpt, EmptyTree) :: Nil, body) =>
tpt match {
case SyntacticEmptyTypeTree() => Some((Bind(name, global.Ident(nme.WILDCARD)), body))
case _ => Some((Bind(name, Typed(global.Ident(nme.WILDCARD), tpt)), body))
}
case UnVisitor(_, CaseDef(pat, EmptyTree, body) :: Nil) =>
Some((pat, body))
case _ => None
}
}
// match call to either withFilter or filter
protected object FilterCall {
def unapply(tree: Tree): Option[(Tree,Tree)] = tree match {
case Apply(Select(obj, nme.withFilter | nme.filter), arg :: Nil) =>
Some(obj, arg)
case _ => None
}
}
// transform a chain of withFilter calls into a sequence of for filters
protected object UnFilter {
def unapply(tree: Tree): Some[(Tree, List[Tree])] = tree match {
case UnCheckIfRefutable(_, _) =>
Some((tree, Nil))
case FilterCall(UnFilter(rhs, rest), UnClosure(_, test)) =>
Some((rhs, rest :+ SyntacticFilter(test)))
case _ =>
Some((tree, Nil))
}
}
// undo gen.mkCheckIfRefutable
protected object UnCheckIfRefutable {
def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
case FilterCall(rhs, UnVisitor(name,
CaseDef(pat, EmptyTree, Literal(Constant(true))) ::
CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))) :: Nil))
if name.toString.contains(nme.CHECK_IF_REFUTABLE_STRING) =>
Some((pat, rhs))
case _ => None
}
}
// undo gen.mkFor:makeCombination accounting for possible extra implicit argument
protected class UnForCombination(name: TermName) {
def unapply(tree: Tree) = tree match {
case SyntacticApplied(SyntacticTypeApplied(sel @ Select(lhs, meth), _), (f :: Nil) :: Nil)
if name == meth && sel.hasAttachment[ForAttachment.type] =>
Some(lhs, f)
case SyntacticApplied(SyntacticTypeApplied(sel @ Select(lhs, meth), _), (f :: Nil) :: _ :: Nil)
if name == meth && sel.hasAttachment[ForAttachment.type] =>
Some(lhs, f)
case _ => None
}
}
protected object UnMap extends UnForCombination(nme.map)
protected object UnForeach extends UnForCombination(nme.foreach)
protected object UnFlatMap extends UnForCombination(nme.flatMap)
// undo desugaring done in gen.mkFor
protected object UnFor {
def unapply(tree: Tree): Option[(List[Tree], Tree)] = {
val interm = tree match {
case UnFlatMap(UnFilter(rhs, filters), UnClosure(pat, UnFor(rest, body))) =>
Some(((pat, rhs), filters ::: rest, body))
case UnForeach(UnFilter(rhs, filters), UnClosure(pat, UnFor(rest, body))) =>
Some(((pat, rhs), filters ::: rest, body))
case UnMap(UnFilter(rhs, filters), UnClosure(pat, cbody)) =>
Some(((pat, rhs), filters, gen.Yield(cbody)))
case UnForeach(UnFilter(rhs, filters), UnClosure(pat, cbody)) =>
Some(((pat, rhs), filters, cbody))
case _ => None
}
interm.flatMap {
case ((Bind(_, SyntacticTuple(_)) | SyntacticTuple(_),
UnFor(SyntacticValFrom(pat, rhs) :: innerRest, gen.Yield(UnPatSeqWithRes(pats, elems2)))),
outerRest, fbody) =>
val valeqs = pats.map { case (pat, rhs) => SyntacticValEq(pat, rhs) }
Some((SyntacticValFrom(pat, rhs) :: innerRest ::: valeqs ::: outerRest, fbody))
case ((pat, rhs), filters, body) =>
Some((SyntacticValFrom(pat, rhs) :: filters, body))
}
}
}
// check that enumerators are valid
protected def mkEnumerators(enums: List[Tree]): List[Tree] = {
require(enums.nonEmpty, "enumerators can't be empty")
enums.head match {
case SyntacticValFrom(_, _) =>
case t => throw new IllegalArgumentException(s"$t is not a valid fist enumerator of for loop")
}
enums.tail.foreach {
case SyntacticValEq(_, _) | SyntacticValFrom(_, _) | SyntacticFilter(_) =>
case t => throw new IllegalArgumentException(s"$t is not a valid representation of a for loop enumerator")
}
enums
}
object SyntacticFor {
def apply(enums: List[Tree], body: Tree): Tree = gen.mkFor(mkEnumerators(enums), body)
def unapply(tree: Tree) = tree match {
case UnFor(enums, gen.Yield(body)) => None
case UnFor(enums, body) => Some((enums, body))
case _ => None
}
}
object SyntacticForYield {
def apply(enums: List[Tree], body: Tree): Tree = gen.mkFor(mkEnumerators(enums), gen.Yield(body))
def unapply(tree: Tree) = tree match {
case UnFor(enums, gen.Yield(body)) => Some((enums, body))
case _ => None
}
}
// use typetree's original instead of typetree itself
protected object MaybeTypeTreeOriginal {
def unapply(tree: Tree): Some[Tree] = tree match {
case tt: TypeTree => Some(tt.original)
case _ => Some(tree)
}
}
// drop potential extra call to .apply
protected object MaybeSelectApply {
def unapply(tree: Tree): Some[Tree] = tree match {
case Select(f, nme.apply) => Some(f)
case other => Some(other)
}
}
// drop potential @scala.unchecked annotation
protected object MaybeUnchecked {
def unapply(tree: Tree): Some[Tree] = tree match {
case Annotated(SyntacticNew(Nil, ScalaDot(tpnme.unchecked) :: Nil, emptyValDef, Nil), annottee) =>
Some(annottee)
case Typed(annottee, MaybeTypeTreeOriginal(
Annotated(SyntacticNew(Nil, ScalaDot(tpnme.unchecked) :: Nil, emptyValDef, Nil), _))) =>
Some(annottee)
case annottee => Some(annottee)
}
}
protected object MaybeTyped {
def unapply(tree: Tree): Some[(Tree, Tree)] = tree match {
case Typed(v, tpt) => Some((v, tpt))
case v => Some((v, SyntacticEmptyTypeTree()))
}
}
protected def mkCases(cases: List[Tree]): List[CaseDef] = cases.map {
case c: CaseDef => c
case tree => throw new IllegalArgumentException("$tree is not valid representation of pattern match case")
}
object SyntacticPartialFunction {
def apply(cases: List[Tree]): Match = Match(EmptyTree, mkCases(cases))
def unapply(tree: Tree): Option[List[CaseDef]] = tree match {
case Match(EmptyTree, cases) => Some(cases)
case Typed(
Block(
List(ClassDef(clsMods, tpnme.ANON_FUN_NAME, Nil, Template(
List(abspf: TypeTree, ser: TypeTree), noSelfType, List(
DefDef(_, nme.CONSTRUCTOR, _, _, _, _),
DefDef(_, nme.applyOrElse, _, _, _,
Match(_, cases :+
CaseDef(Bind(nme.DEFAULT_CASE, Ident(nme.WILDCARD)), _, _))),
DefDef(_, nme.isDefinedAt, _, _, _, _))))),
Apply(Select(New(Ident(tpnme.ANON_FUN_NAME)), nme.CONSTRUCTOR), List())),
pf: TypeTree)
if pf.tpe != null && pf.tpe.typeSymbol.eq(PartialFunctionClass) &&
abspf.tpe != null && abspf.tpe.typeSymbol.eq(AbstractPartialFunctionClass) &&
ser.tpe != null && ser.tpe.typeSymbol.eq(SerializableClass) &&
clsMods.hasFlag(FINAL) && clsMods.hasFlag(SYNTHETIC) =>
Some(cases)
case _ => None
}
}
object SyntacticMatch {
def apply(scrutinee: Tree, cases: List[Tree]) = {
require(scrutinee.nonEmpty, "match's scrutinee may not be empty")
Match(scrutinee, mkCases(cases))
}
def unapply(tree: Match): Option[(Tree, List[CaseDef])] = tree match {
case Match(scrutinee, cases) if scrutinee.nonEmpty => Some((scrutinee, cases))
case _ => None
}
}
object SyntacticTry {
def apply(block: Tree, catches: List[Tree], finalizer: Tree) = Try(block, mkCases(catches), finalizer)
def unapply(tree: Try): Option[(Tree, List[CaseDef], Tree)] = Try.unapply(tree)
}
object SyntacticTermIdent {
def apply(name: TermName, isBackquoted: Boolean): Ident = {
val id = Ident(name)
if (isBackquoted) id my_updateAttachment BackquotedIdentifierAttachment
id
}
def unapply(id: Ident): Option[(TermName, Boolean)] = id.name match {
case name: TermName => Some((name, id.hasAttachment[BackquotedIdentifierAttachment.type]))
case _ => None
}
}
object SyntacticTypeIdent {
def apply(name: TypeName): Ident = Ident(name)
def unapply(tree: Tree): Option[TypeName] = tree match {
case MaybeTypeTreeOriginal(Ident(name: TypeName)) => Some(name)
case _ => None
}
}
/** Facade over Imports and ImportSelectors that lets to structurally
* deconstruct/reconstruct them.
*
* Selectors are represented in the following way:
* 1. q"import foo._" <==> q"import foo.${pq"_"}"
* 2. q"import foo.bar" <==> q"import foo.${pq"bar"}"
* 3. q"import foo.{bar => baz}" <==> q"import foo.${pq"bar -> baz"}"
* 4. q"import foo.{bar => _}" <==> q"import foo.${pq"bar -> _"}"
*
* All names in selectors are TermNames despite the fact ImportSelector
* can theoretically contain TypeNames too (but they never do in practice.)
*/
object SyntacticImport {
// construct/deconstruct {_} import selector
private object WildcardSelector {
def apply(offset: Int): ImportSelector = ImportSelector(nme.WILDCARD, offset, null, -1)
def unapply(sel: ImportSelector): Option[Int] = sel match {
case ImportSelector(nme.WILDCARD, offset, null, -1) => Some(offset)
case _ => None
}
}
// construct/deconstruct {foo} import selector
private object NameSelector {
def apply(name: TermName, offset: Int): ImportSelector = ImportSelector(name, offset, name, offset)
def unapply(sel: ImportSelector): Option[(TermName, Int)] = sel match {
case ImportSelector(name1, offset1, name2, offset2) if name1 == name2 && offset1 == offset2 =>
Some((name1.toTermName, offset1))
case _ =>
None
}
}
// construct/deconstruct {foo => bar} import selector
private object RenameSelector {
def apply(name1: TermName, offset1: Int, name2: TermName, offset2: Int): ImportSelector =
ImportSelector(name1, offset1, name2, offset2)
def unapply(sel: ImportSelector): Option[(TermName, Int, TermName, Int)] = sel match {
case ImportSelector(_, _, null | nme.WILDCARD, _) =>
None
case ImportSelector(name1, offset1, name2, offset2) if name1 != name2 =>
Some((name1.toTermName, offset1, name2.toTermName, offset2))
case _ =>
None
}
}
// construct/deconstruct {foo => _} import selector
private object UnimportSelector {
def apply(name: TermName, offset: Int): ImportSelector =
ImportSelector(name, offset, nme.WILDCARD, -1)
def unapply(sel: ImportSelector): Option[(TermName, Int)] = sel match {
case ImportSelector(name, offset, nme.WILDCARD, _) => Some((name.toTermName, offset))
case _ => None
}
}
// represent {_} import selector as pq"_"
private object WildcardSelectorRepr {
def apply(pos: Position): Tree = atPos(pos)(global.Ident(nme.WILDCARD))
def unapply(tree: Tree): Option[Position] = tree match {
case global.Ident(nme.WILDCARD) => Some(tree.pos)
case _ => None
}
}
// represent {foo} import selector as pq"foo"
private object NameSelectorRepr {
def apply(name: TermName, pos: Position): Tree = atPos(pos)(Bind(name, WildcardSelectorRepr(pos)))
def unapply(tree: Tree): Option[(TermName, Position)] = tree match {
case Bind(name, WildcardSelectorRepr(_)) => Some((name.toTermName, tree.pos))
case _ => None
}
}
// pq"left -> right"
private object Arrow {
def apply(left: Tree, right: Tree): Apply =
Apply(global.Ident(nme.MINGT), left :: right :: Nil)
def unapply(tree: Apply): Option[(Tree, Tree)] = tree match {
case Apply(global.Ident(nme.MINGT), left :: right :: Nil) => Some((left, right))
case _ => None
}
}
// represent {foo => bar} import selector as pq"foo -> bar"
private object RenameSelectorRepr {
def apply(name1: TermName, pos1: Position, name2: TermName, pos2: Position): Tree = {
val left = NameSelectorRepr(name1, pos1)
val right = NameSelectorRepr(name2, pos2)
atPos(wrappingPos(left :: right :: Nil))(Arrow(left, right))
}
def unapply(tree: Tree): Option[(TermName, Position, TermName, Position)] = tree match {
case Arrow(NameSelectorRepr(name1, pos1), NameSelectorRepr(name2, pos2)) =>
Some((name1.toTermName, pos1, name2.toTermName, pos2))
case _ =>
None
}
}
// represent {foo => _} import selector as pq"foo -> _"
private object UnimportSelectorRepr {
def apply(name: TermName, pos: Position): Tree =
atPos(pos)(Arrow(NameSelectorRepr(name, pos), WildcardSelectorRepr(pos)))
def unapply(tree: Tree): Option[(TermName, Position)] = tree match {
case Arrow(NameSelectorRepr(name, pos), WildcardSelectorRepr(_)) =>
Some((name, pos))
case _ =>
None
}
}
private def derivedPos(t: Tree, offset: Int): Position =
if (t.pos == NoPosition) NoPosition else t.pos.withPoint(offset)
private def derivedOffset(pos: Position): Int =
if (pos == NoPosition) -1 else pos.point
def apply(expr: Tree, selectors: List[Tree]): Import = {
val importSelectors = selectors.map {
case WildcardSelectorRepr(pos) => WildcardSelector(derivedOffset(pos))
case NameSelectorRepr(name, pos) => NameSelector(name, derivedOffset(pos))
case RenameSelectorRepr(name1, pos1, name2, pos2) => RenameSelector(name1, derivedOffset(pos1), name2, derivedOffset(pos2))
case UnimportSelectorRepr(name, pos) => UnimportSelector(name, derivedOffset(pos))
case tree => throw new IllegalArgumentException(s"${showRaw(tree)} doesn't correspond to import selector")
}
Import(expr, importSelectors)
}
def unapply(imp: Import): Some[(Tree, List[Tree])] = {
val selectors = imp.selectors.map {
case WildcardSelector(offset) => WildcardSelectorRepr(derivedPos(imp, offset))
case NameSelector(name, offset) => NameSelectorRepr(name, derivedPos(imp, offset))
case RenameSelector(name1, offset1, name2, offset2) => RenameSelectorRepr(name1, derivedPos(imp, offset1), name2, derivedPos(imp, offset2))
case UnimportSelector(name, offset) => UnimportSelectorRepr(name, derivedPos(imp, offset))
}
Some((imp.expr, selectors))
}
}
object SyntacticSelectType {
def apply(qual: Tree, name: TypeName): Select = Select(qual, name)
def unapply(tree: Tree): Option[(Tree, TypeName)] = tree match {
case MaybeTypeTreeOriginal(Select(qual, name: TypeName)) => Some((qual, name))
case _ => None
}
}
object SyntacticSelectTerm {
def apply(qual: Tree, name: TermName): Select = Select(qual, name)
def unapply(tree: Tree): Option[(Tree, TermName)] = tree match {
case Select(qual, name: TermName) => Some((qual, name))
case _ => None
}
}
object SyntacticCompoundType {
def apply(parents: List[Tree], defns: List[Tree]) =
CompoundTypeTree(Template(gen.mkParents(NoMods, parents), emptyValDef, defns))
def unapply(tree: Tree): Option[(List[Tree], List[Tree])] = tree match {
case MaybeTypeTreeOriginal(CompoundTypeTree(Template(parents, _, defns))) =>
Some((parents, defns))
case _ =>
None
}
}
object SyntacticSingletonType {
def apply(ref: Tree): SingletonTypeTree = SingletonTypeTree(ref)
def unapply(tree: Tree): Option[Tree] = tree match {
case MaybeTypeTreeOriginal(SingletonTypeTree(ref)) =>
Some(ref)
case _ =>
None
}
}
object SyntacticTypeProjection {
def apply(qual: Tree, name: TypeName): SelectFromTypeTree =
SelectFromTypeTree(qual, name)
def unapply(tree: Tree): Option[(Tree, TypeName)] = tree match {
case MaybeTypeTreeOriginal(SelectFromTypeTree(qual, name)) =>
Some((qual, name))
case _ =>
None
}
}
object SyntacticAnnotatedType {
def apply(tpt: Tree, annot: Tree): Annotated =
Annotated(annot, tpt)
def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
case MaybeTypeTreeOriginal(Annotated(annot, tpt)) =>
Some((tpt, annot))
case _ =>
None
}
}
object SyntacticExistentialType {
def apply(tpt: Tree, where: List[Tree]): ExistentialTypeTree =
ExistentialTypeTree(tpt, where.map {
case md: MemberDef => md
case tree => throw new IllegalArgumentException("$tree is not legal forSome definition")
})
def unapply(tree: Tree): Option[(Tree, List[MemberDef])] = tree match {
case MaybeTypeTreeOriginal(ExistentialTypeTree(tpt, where)) =>
Some((tpt, where.asInstanceOf[List[MemberDef]])) // NOTE: in 2.11 where is typed as List[MemberDef], but in 2.10.x it's still List[Tree]
case _ =>
None
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy