summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-11-19 08:39:59 +0000
committerPaul Phillips <paulp@improving.org>2011-11-19 08:39:59 +0000
commit214c145943ac2c6bf37bd40f5e07e225350201c5 (patch)
tree9ae086954e4e855e9561bbef0b812d34c82d967c
parent334872e33be8385678697f3d670c8102d38cdca7 (diff)
downloadscala-214c145943ac2c6bf37bd40f5e07e225350201c5.tar.gz
scala-214c145943ac2c6bf37bd40f5e07e225350201c5.tar.bz2
scala-214c145943ac2c6bf37bd40f5e07e225350201c5.zip
Cleanups in TypeApply creation and casting.
There's every hint that it's a requirement that a TypeApply have non-empty typeArgs, but testing for and handling the empty condition is done irregularly. Made a mkTypeApply which handles the isEmpty case (returning "fun" unchanged.) Also unified most of the variations of casts under one umbrella. Review by moors.
-rw-r--r--src/compiler/scala/reflect/internal/TreeGen.scala50
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala5
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala5
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala14
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala46
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala8
-rw-r--r--src/library/scala/reflect/api/Trees.scala5
13 files changed, 78 insertions, 79 deletions
diff --git a/src/compiler/scala/reflect/internal/TreeGen.scala b/src/compiler/scala/reflect/internal/TreeGen.scala
index fae3975ed5..1c93a904c0 100644
--- a/src/compiler/scala/reflect/internal/TreeGen.scala
+++ b/src/compiler/scala/reflect/internal/TreeGen.scala
@@ -46,10 +46,8 @@ abstract class TreeGen {
def mkMethodCall(receiver: Tree, method: Symbol, targs: List[Type], args: List[Tree]): Tree =
mkMethodCall(Select(receiver, method), targs, args)
- def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree = {
- val typeApplied = if (targs.isEmpty) target else TypeApply(target, targs map TypeTree)
- Apply(typeApplied, args)
- }
+ def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree =
+ Apply(mkTypeApply(target, targs map TypeTree), args)
/** Builds a reference to value whose type is given stable prefix.
* The type must be suitable for this. For example, it
@@ -153,12 +151,14 @@ abstract class TreeGen {
/** Cast `tree` to type `pt` */
def mkCast(tree: Tree, pt: Type): Tree = {
- debuglog("casting " + tree + ":" + tree.tpe + " to " + pt)
+ debuglog("casting " + tree + ":" + tree.tpe + " to " + pt + " at phase: " + phase)
assert(!tree.tpe.isInstanceOf[MethodType], tree)
- assert(!pt.typeSymbol.isPackageClass)
- assert(!pt.typeSymbol.isPackageObjectClass)
- assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize)) //@MAT only called during erasure, which already takes care of that
- atPos(tree.pos)(mkAsInstanceOf(tree, pt, false))
+ assert(!pt.typeSymbol.isPackageClass && !pt.typeSymbol.isPackageObjectClass, pt)
+ // @MAT only called during erasure, which already takes care of that
+ // @PP: "only called during erasure" is not very true these days.
+ // In addition, at least, are: typer, uncurry, explicitouter, cleanup.
+ assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize))
+ atPos(tree.pos)(mkAsInstanceOf(tree, pt, any = false, wrapInApply = true))
}
/** Builds a reference with stable type to given symbol */
@@ -192,31 +192,33 @@ abstract class TreeGen {
}
}
- private def mkTypeApply(value: Tree, tpe: Type, what: Symbol, wrapInApply: Boolean) = {
- val tapp = TypeApply(mkAttributedSelect(value, what), List(TypeTree(tpe.normalize)))
- if (wrapInApply) Apply(tapp, List()) else tapp
+ /** Builds a type application node if args.nonEmpty, returns fun otherwise. */
+ def mkTypeApply(fun: Tree, targs: List[Tree]): Tree =
+ if (targs.isEmpty) fun else TypeApply(fun, targs)
+ def mkTypeApply(target: Tree, method: Symbol, targs: List[Type]): Tree =
+ mkTypeApply(Select(target, method), targs map TypeTree)
+ def mkAttributedTypeApply(target: Tree, method: Symbol, targs: List[Type]): Tree =
+ mkTypeApply(mkAttributedSelect(target, method), targs map TypeTree)
+
+ private def mkSingleTypeApply(value: Tree, tpe: Type, what: Symbol, wrapInApply: Boolean) = {
+ val tapp = mkAttributedTypeApply(value, what, List(tpe.normalize))
+ if (wrapInApply) Apply(tapp, Nil) else tapp
}
+ private def typeTestSymbol(any: Boolean) = if (any) Any_isInstanceOf else Object_isInstanceOf
+ private def typeCastSymbol(any: Boolean) = if (any) Any_asInstanceOf else Object_asInstanceOf
/** Builds an instance test with given value and type. */
def mkIsInstanceOf(value: Tree, tpe: Type, any: Boolean = true, wrapInApply: Boolean = true): Tree =
- mkTypeApply(value, tpe, (if (any) Any_isInstanceOf else Object_isInstanceOf), wrapInApply)
+ mkSingleTypeApply(value, tpe, typeTestSymbol(any), wrapInApply)
/** Builds a cast with given value and type. */
def mkAsInstanceOf(value: Tree, tpe: Type, any: Boolean = true, wrapInApply: Boolean = true): Tree =
- mkTypeApply(value, tpe, (if (any) Any_asInstanceOf else Object_asInstanceOf), wrapInApply)
+ mkSingleTypeApply(value, tpe, typeCastSymbol(any), wrapInApply)
/** Cast `tree` to `pt`, unless tpe is a subtype of pt, or pt is Unit. */
def maybeMkAsInstanceOf(tree: Tree, pt: Type, tpe: Type, beforeRefChecks: Boolean = false): Tree =
- if ((pt == UnitClass.tpe) || (tpe <:< pt)) {
- log("no need to cast from " + tpe + " to " + pt)
- tree
- } else
- atPos(tree.pos) {
- if (beforeRefChecks)
- TypeApply(mkAttributedSelect(tree, Any_asInstanceOf), List(TypeTree(pt)))
- else
- mkAsInstanceOf(tree, pt)
- }
+ if ((pt == UnitClass.tpe) || (tpe <:< pt)) tree
+ else atPos(tree.pos)(mkAsInstanceOf(tree, pt, any = true, wrapInApply = !beforeRefChecks))
/** Apparently we smuggle a Type around as a Literal(Constant(tp))
* and the implementation of Constant#tpe is such that x.tpe becomes
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index f8255bc846..85a12193a9 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -2986,6 +2986,11 @@ A type's typeSymbol should never be inspected directly.
/** A creator for type parameterizations that strips empty type parameter lists.
* Use this factory method to indicate the type has kind * (it's a polymorphic value)
* until we start tracking explicit kinds equivalent to typeFun (except that the latter requires tparams nonEmpty).
+ *
+ * PP to AM: I've co-opted this for where I know tparams may well be empty, and
+ * expecting to get back `tpe` in such cases. Re being "forgiving" below,
+ * can we instead say this is the canonical creator for polyTypes which
+ * may or may not be poly? (It filched the standard "canonical creator" name.)
*/
def polyType(tparams: List[Symbol], tpe: Type): Type =
if (tparams nonEmpty) typeFun(tparams, tpe)
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index 8add556741..efc64dbbc5 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -114,10 +114,7 @@ trait TreeDSL {
*
* See ticket #2168 for one illustration of AS vs. AS_ANY.
*/
- def AS(tpe: Type) = TypeApply(Select(target, Any_asInstanceOf), List(TypeTree(tpe)))
- def AS_ANY(tpe: Type) = gen.mkAsInstanceOf(target, tpe)
- def AS_ATTR(tpe: Type) = gen.mkAttributedCast(target, tpe)
-
+ def AS(tpe: Type) = gen.mkAsInstanceOf(target, tpe, any = true, wrapInApply = false)
def IS(tpe: Type) = gen.mkIsInstanceOf(target, tpe, true)
def IS_OBJ(tpe: Type) = gen.mkIsInstanceOf(target, tpe, false)
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index b073bb3c96..481a997c00 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -24,7 +24,10 @@ trait ParallelMatching extends ast.TreeDSL
self: ExplicitOuter =>
import global.{ typer => _, _ }
- import definitions.{ AnyRefClass, NothingClass, IntClass, BooleanClass, SomeClass, OptionClass, getProductArgs, productProj }
+ import definitions.{
+ AnyRefClass, NothingClass, IntClass, BooleanClass, SomeClass, OptionClass,
+ getProductArgs, productProj, Object_eq, Any_asInstanceOf
+ }
import CODE._
import Types._
import Debug._
@@ -132,7 +135,7 @@ trait ParallelMatching extends ast.TreeDSL
def castedTo(headType: Type) =
if (tpe =:= headType) this
- else new Scrutinee(createVar(headType, lhs => id AS_ANY lhs.tpe))
+ else new Scrutinee(createVar(headType, lhs => gen.mkAsInstanceOf(id, lhs.tpe)))
override def toString() = "(%s: %s)".format(id, tpe)
}
@@ -673,7 +676,7 @@ trait ParallelMatching extends ast.TreeDSL
// the val definition's type, or a casted Ident if not.
private def newValIdent(lhs: Symbol, rhs: Symbol) =
if (rhs.tpe <:< lhs.tpe) Ident(rhs)
- else Ident(rhs) AS lhs.tpe
+ else gen.mkTypeApply(Ident(rhs), Any_asInstanceOf, List(lhs.tpe))
protected def newValDefinition(lhs: Symbol, rhs: Symbol) =
typer typedValDef ValDef(lhs, newValIdent(lhs, rhs))
@@ -854,10 +857,11 @@ trait ParallelMatching extends ast.TreeDSL
case ThisType(clazz) => THIS(clazz)
case pre => REF(pre.prefix, pre.termSymbol)
})
-
outerAccessor(tpe2test.typeSymbol) match {
case NoSymbol => ifDebug(cunit.warning(scrut.pos, "no outer acc for " + tpe2test.typeSymbol)) ; cond
- case outerAcc => cond AND (((scrut AS_ANY tpe2test) DOT outerAcc)() OBJ_EQ theRef)
+ case outerAcc =>
+ val casted = gen.mkAsInstanceOf(scrut, tpe2test, any = true, wrapInApply = true)
+ cond AND ((casted DOT outerAcc)() OBJ_EQ theRef)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index 9f15c768e3..d001a0af8b 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -245,7 +245,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
def mkNewPolyCache = gen.mkSoftRef(NEW(TypeTree(EmptyMethodCacheClass.tpe)))
val reflPolyCacheSym: Symbol = addStaticVariableToClass("reflPoly$Cache", SoftReferenceClass.tpe, mkNewPolyCache, false)
- def getPolyCache = fn(safeREF(reflPolyCacheSym), nme.get) AS_ATTR MethodCacheClass.tpe
+ def getPolyCache = gen.mkCast(fn(safeREF(reflPolyCacheSym), nme.get), MethodCacheClass.tpe)
addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe)
{ case Pair(reflMethodSym, List(forReceiverSym)) =>
@@ -405,7 +405,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
def fixResult(tree: Tree, mustBeUnit: Boolean = false) =
if (mustBeUnit || resultSym == UnitClass) BLOCK(tree, REF(BoxedUnit_UNIT)) // boxed unit
else if (resultSym == ObjectClass) tree // no cast necessary
- else tree AS_ATTR boxedResType // cast to expected type
+ else gen.mkCast(tree, boxedResType) // cast to expected type
/** Normal non-Array call */
def genDefaultCall = {
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index a2eddd34bd..9806857ff2 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -490,7 +490,7 @@ abstract class Erasure extends AddInterfaces
log("Attempted to cast to Unit: " + tree)
tree.duplicate setType pt
}
- else tree AS_ATTR pt
+ else gen.mkAttributedCast(tree, pt)
}
private def isUnboxedValueMember(sym: Symbol) =
@@ -1002,7 +1002,7 @@ abstract class Erasure extends AddInterfaces
if (isAccessible(qualSym) && !qualSym.isPackageClass && !qualSym.isPackageObjectClass) {
// insert cast to prevent illegal access error (see #4283)
// util.trace("insert erasure cast ") (*/
- treeCopy.Select(tree, qual AS_ATTR qual.tpe.widen, name) //)
+ treeCopy.Select(tree, gen.mkAttributedCast(qual, qual.tpe.widen), name) //)
} else tree
} else tree
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 192c4e9b59..fcc03a82d0 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -359,7 +359,7 @@ abstract class ExplicitOuter extends InfoTransform
localTyper typed {
(DEF(outerAcc) withPos currentClass.pos) === {
// Need to cast for nested outer refs in presence of self-types. See ticket #3274.
- transformer.transform(path) AS_ANY outerAcc.info.resultType
+ gen.mkCast(transformer.transform(path), outerAcc.info.resultType)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 97f204bc41..212785a525 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -1084,34 +1084,31 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case _ => //log("nope")
}
+ private def unspecializableClass(tp: Type) = (
+ definitions.isRepeatedParamType(tp) // ???
+ || tp.typeSymbol.isJavaDefined
+ || tp.typeSymbol.isPackageClass
+ )
+
/** Type transformation. It is applied to all symbols, compiled or loaded.
* If it is a 'no-specialization' run, it is applied only to loaded symbols.
*/
override def transformInfo(sym: Symbol, tpe: Type): Type = {
if (settings.nospecialization.value && currentRun.compiles(sym)) tpe
- else tpe match {
- case PolyType(targs, ClassInfoType(base, decls, clazz))
- if clazz != RepeatedParamClass
- && clazz != JavaRepeatedParamClass
- && !clazz.isJavaDefined =>
- val parents = base map specializedType
- debuglog("transformInfo (poly) " + clazz + " with parents1: " + parents + " ph: " + phase)
-
- polyType(targs, ClassInfoType(
- parents,
- new Scope(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz)),
- clazz)
- )
- case ClassInfoType(base, decls, clazz) if !clazz.isPackageClass && !clazz.isJavaDefined =>
- atPhase(phase.next)(base map (_.typeSymbol.info))
- // side effecting? parents is not used except to log.
- val parents = base map specializedType
- debuglog("transformInfo " + clazz + " with parents1: " + parents + " ph: " + phase)
- ClassInfoType(
- base map specializedType,
- new Scope(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz)),
- clazz
+ else tpe.resultType match {
+ case cinfo @ ClassInfoType(parents, decls, clazz) if !unspecializableClass(cinfo) =>
+ val tparams = tpe.typeParams
+ if (tparams.isEmpty)
+ atPhase(phase.next)(parents map (_.typeSymbol.info))
+
+ val parents1 = parents map specializedType
+ debuglog("transformInfo %s %s with parents1 %s ph: %s".format(
+ if (tparams.nonEmpty) " (poly)" else "",
+ clazz, parents1, phase)
)
+ val newScope = new Scope(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz))
+ // If tparams.isEmpty, this is just the ClassInfoType.
+ polyType(tparams, ClassInfoType(parents1, newScope, clazz))
case _ =>
tpe
}
@@ -1292,9 +1289,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
} else None
}
- def maybeTypeApply(fun: Tree, targs: List[Tree]) =
- if (targs.isEmpty) fun else TypeApply(fun, targs)
-
curTree = tree
tree match {
case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
@@ -1333,7 +1327,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
"residual: %s, tparams: %s, env: %s".format(residualTargs, symbol.info.typeParams, env))
)
- val tree1 = maybeTypeApply(Select(qual1, specMember), residualTargs)
+ val tree1 = gen.mkTypeApply(Select(qual1, specMember), residualTargs)
log("rewrote " + tree + " to " + tree1)
localTyper.typedOperator(atPos(tree.pos)(tree1)) // being polymorphic, it must be a method
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index c5237b4d59..50ebb2b3a5 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -306,7 +306,7 @@ abstract class UnCurry extends InfoTransform
else if (IntClass.tpe <:< a.tpe) Literal(Constant(0))
else if (LongClass.tpe <:< a.tpe) Literal(Constant(0L))
else if (CharClass.tpe <:< a.tpe) Literal(Constant(0.toChar))
- else NULL AS a.tpe // must cast, at least when a.tpe <:< NothingClass.tpe
+ else gen.mkCast(NULL, a.tpe) // must cast, at least when a.tpe <:< NothingClass.tpe
Apply(fun.duplicate, List(zero))
case _ =>
super.transform(tree)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index b67198a292..a355085246 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1081,12 +1081,10 @@ trait Implicits {
manifestFactoryCall("arrayType", args.head, findManifest(args.head))
} else if (sym.isClass) {
val classarg0 = gen.mkClassOf(tp1)
- val classarg = (
- if (tp.isInstanceOf[ExistentialType])
- TypeApply(Select(classarg0, Any_asInstanceOf), List(TypeTree(ClassType(tp))))
- else
- classarg0
- )
+ val classarg = tp match {
+ case _: ExistentialType => gen.mkCast(classarg0, ClassType(tp))
+ case _ => classarg0
+ }
val suffix = classarg :: (args map findSubManifest)
manifestFactoryCall(
"classType", tp,
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 3591732c70..cf8c0c596c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -282,7 +282,7 @@ trait SyntheticMethods extends ast.TreeDSL {
def equalsClassMethod: Tree = createMethod(nme.equals_, List(AnyClass.tpe), BooleanClass.tpe) { m =>
val arg0 = methodArg(m, 0)
val thatTest = gen.mkIsInstanceOf(arg0, clazzTypeToTest(clazz), true, false)
- val thatCast = arg0 AS_ATTR clazz.tpe
+ val thatCast = gen.mkCast(arg0, clazz.tpe)
def argsBody: Tree = {
val otherName = context.unit.freshTermName(clazz.name + "$")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 65eb6466df..41e0819fe2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1913,12 +1913,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (!context.savedTypeBounds.isEmpty) {
body1.tpe = context.restoreTypeBounds(body1.tpe)
if (isFullyDefined(pt) && !(body1.tpe <:< pt)) {
- body1 =
- typed {
- atPos(body1.pos) {
- TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt))) // @M no need for pt.normalize here, is done in erasure
- }
- }
+ // @M no need for pt.normalize here, is done in erasure
+ body1 = typedPos(body1.pos)(gen.mkCast(body1, pt))
}
}
// body1 = checkNoEscaping.locals(context.scope, pt, body1)
diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala
index 3e5dae739d..64793fb303 100644
--- a/src/library/scala/reflect/api/Trees.scala
+++ b/src/library/scala/reflect/api/Trees.scala
@@ -496,7 +496,10 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
}
/** Explicit type application.
- */
+ * @PP: All signs point toward it being a requirement that args.nonEmpty,
+ * but I can't find that explicitly stated anywhere. Unless your last name
+ * is odersky, you should probably treat it as true.
+ */
case class TypeApply(fun: Tree, args: List[Tree])
extends GenericApply {
override def symbol: Symbol = fun.symbol