diff options
author | Paul Phillips <paulp@improving.org> | 2011-11-19 08:39:59 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-11-19 08:39:59 +0000 |
commit | 214c145943ac2c6bf37bd40f5e07e225350201c5 (patch) | |
tree | 9ae086954e4e855e9561bbef0b812d34c82d967c /src/compiler | |
parent | 334872e33be8385678697f3d670c8102d38cdca7 (diff) | |
download | scala-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.
Diffstat (limited to 'src/compiler')
12 files changed, 74 insertions, 78 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) |