scala.tools.nsc.tasty.bridge.TreeOps.scala Maven / Gradle / Ivy
The newest version!
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala.tools.nsc.tasty.bridge
import scala.tools.nsc.tasty.{TastyUniverse, TastyModes}, TastyModes._
import scala.tools.tasty.TastyName
import scala.reflect.internal.Flags
/**This layer adds factories that construct typed `scala.reflect` Trees in the shapes that TASTy expects
*/
trait TreeOps { self: TastyUniverse =>
import self.{symbolTable => u}
object untpd {
final val EmptyTree: Tree = u.EmptyTree
}
private class TastyIdent(val tname: TastyName) extends u.Ident(encodeTastyName(tname))
implicit class TreeDecorator(val tree: Tree) {
def typeIdent: TastyName.TypeName = tree match {
case tree: TastyIdent => tree.tname.toTypeName
case _ => TastyName.EmptyTpe
}
}
def showTree(tree: Tree)(implicit ctx: Context): String = {
// here we want to avoid forcing the symbols of type trees,
// so instead substitute the type tree with an Identifier
// of the `showType`, which does not force.
val tree1 = tree.transform(new u.Transformer {
override def transform(tree: Tree) = tree match {
case tree: u.TypeTree => u.Ident(s"${showType(tree.tpe, wrap = false)}") // ident prints its name directly
case tree => super.transform(tree)
}
})
u.show(tree1)
}
object tpd {
@inline final def Constant(value: Any): Constant =
u.Constant(value)
@inline final def Ident(name: TastyName)(tpe: Type): Tree =
new TastyIdent(name).setType(tpe)
@inline final def Select(qual: Tree, name: TastyName)(implicit ctx: Context): Tree =
selectImpl(qual, name)(implicit ctx => lookupTypeFrom(qual.tpe)(qual.tpe, name))
@inline final def Select(owner: Type)(qual: Tree, name: TastyName)(implicit ctx: Context): Tree =
selectImpl(qual, name)(implicit ctx => lookupTypeFrom(owner)(qual.tpe, name))
private def selectImpl(qual: Tree, name: TastyName)(lookup: Context => Type)(implicit ctx: Context): Tree = {
def selectName(qual: Tree, name: TastyName)(lookup: Context => Type) =
u.Select(qual, encodeTastyName(name)).setType(lookup(ctx))
def selectCtor(qual: Tree) =
u.Select(qual, u.nme.CONSTRUCTOR).setType(qual.tpe.typeSymbol.primaryConstructor.tpe)
if (ctx.mode.is(ReadAnnotationCtor) && name.isSignedConstructor)
selectCtor(qual)
else
selectName(qual, name)(lookup)
}
@inline final def This(qual: TastyName.TypeName)(tpe: Type): Tree =
u.This(encodeTypeName(qual)).setType(tpe)
@inline final def New(tpt: Tree): Tree =
u.New(tpt).setType(safeClassType(tpt.tpe))
@inline final def SingletonTypeTree(ref: Tree): Tree =
u.SingletonTypeTree(ref).setType(ref.tpe)
@inline final def ByNameTypeTree(arg: Tree): Tree =
u.gen.mkFunctionTypeTree(Nil, arg).setType(u.definitions.byNameType(arg.tpe))
@inline final def NamedArg(name: TastyName, value: Tree): Tree =
u.NamedArg(u.Ident(encodeTastyName(name)), value).setType(value.tpe)
def Super(qual: Tree, mixId: TastyName.TypeName)(mixTpe: Type): Tree = {
val owntype = (
if (!mixId.isEmpty) mixTpe
else u.intersectionType(qual.tpe.parents)
)
u.Super(qual, encodeTypeName(mixId)).setType(u.SuperType(qual.tpe, owntype))
}
def PathTree(tpe: Type): Tree = tpe match {
case _:u.TypeRef | _:u.SingleType => u.TypeTree(tpe)
case path: u.ThisType => u.This(path.sym.name.toTypeName).setType(path)
case path: u.ConstantType => u.Literal(path.value).setType(tpe)
case x => throw new MatchError(x)
}
@inline final def TypeTree(tp: Type): Tree = u.TypeTree(tp)
@inline final def LambdaTypeTree(tparams: List[Symbol], body: Tree): Tree =
u.TypeTree(defn.LambdaFromParams(tparams, body.tpe))
def Macro(impl: Tree): Tree = impl match {
case tree @ u.TypeApply(qual, args) =>
u.TypeApply(Macro(qual), args).setType(tree.tpe)
case tree @ u.Select(pre, sel) =>
val sym = if (sel.isTermName) tree.tpe.termSymbol else tree.tpe.typeSymbol
u.Select(Macro(pre), sym).setType(tree.tpe)
case tree: u.TypeTree if tree.tpe.prefix !== u.NoType =>
val sym = tree.tpe match {
case u.SingleType(_, sym) => sym
case u.TypeRef(_, sym, _) => sym
case u.ThisType(sym) => sym
case x => throw new MatchError(x)
}
if (tree.tpe.prefix === u.NoPrefix && (sym.hasFlag(Flags.PACKAGE) && !sym.isPackageObjectOrClass || sym.isLocalToBlock)) {
if (sym.isLocalToBlock) u.Ident(sym).setType(tree.tpe)
else u.This(sym).setType(tree.tpe)
}
else {
u.Select(Macro(u.TypeTree(tree.tpe.prefix)), sym).setType(tree.tpe)
}
case tree =>
tree
}
@inline final def Typed(expr: Tree, tpt: Tree): Tree = u.Typed(expr, tpt).setType(tpt.tpe)
@inline final def Apply(fun: Tree, args: List[Tree]): Tree = u.Apply(fun, args).setType(fnResult(fun.tpe))
def TypeApply(fun: Tree, args: List[Tree]): Tree = {
if (u.definitions.isPredefMemberNamed(fun.tpe.termSymbol, u.TermName("classOf"))) {
assert(args.length == 1 && !fun.tpe.termSymbol.isOverloaded)
u.Literal(Constant(args.head.tpe))
}
else {
u.TypeApply(fun, args).setType(tyconResult(fun.tpe, args.map(_.tpe)))
}
}
def If(cond: Tree, thenp: Tree, elsep: Tree): Tree =
u.If(cond, thenp, elsep).setType(
if (elsep === u.EmptyTree) u.definitions.UnitTpe
else u.lub(thenp.tpe :: elsep.tpe :: Nil)
)
@inline final def SeqLiteral(trees: List[Tree], tpt: Tree): Tree = u.ArrayValue(tpt, trees).setType(tpt.tpe)
def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit ctx: Context): Tree = {
if (tpt.tpe === AndTpe) {
u.CompoundTypeTree(u.Template(args, u.noSelfType, Nil)).setType(u.intersectionType(args.map(_.tpe)))
}
else if (ctx.isJava && u.definitions.isScalaRepeatedParamType(tpt.tpe)) {
u.AppliedTypeTree(tpt, args).setType(u.definitions.javaRepeatedType(args.head.tpe))
}
else {
u.AppliedTypeTree(tpt, args).setType(defn.AppliedType(tpt.tpe, args.map(_.tpe)))
}
}
def Annotated(tpt: Tree, annot: Tree)(implicit ctx: Context): Tree = {
if (annot.tpe.typeSymbol === defn.RepeatedAnnot
&& tpt.tpe.typeSymbol.isSubClass(u.definitions.SeqClass)
&& tpt.tpe.typeArgs.length == 1) {
if (ctx.isJava) tpd.TypeTree(u.definitions.javaRepeatedType(tpt.tpe.typeArgs.head))
else tpd.TypeTree(u.definitions.scalaRepeatedType(tpt.tpe.typeArgs.head))
}
else {
u.Annotated(annot, tpt).setType(defn.AnnotatedType(tpt.tpe, annot))
}
}
def RefinedTypeTree(parent: Tree, decls: List[Tree], refinedCls: Symbol)(implicit ctx: Context): Tree = {
refinedCls.info.parents.head match {
case defn.PolyFunctionType() =>
val polyType = refinedCls.info.decls.map(_.tpe).headOption.fold(defn.NoType)(x => x)
polyFuncIsUnsupported(polyType)
case _ =>
u.CompoundTypeTree(u.Template(parent :: Nil, u.noSelfType, decls)).setType(refinedCls.info)
}
}
def TypeBoundsTree(lo: Tree, hi: Tree, alias: Tree): Tree = {
val tpe = alias match {
case untpd.EmptyTree => u.TypeBounds(lo.tpe, hi.tpe)
case alias => new OpaqueTypeBounds(lo.tpe, hi.tpe, alias.tpe)
}
u.TypeBoundsTree(lo, hi).setType(tpe)
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy