summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2011-07-19 13:57:37 +0000
committerMartin Odersky <odersky@gmail.com>2011-07-19 13:57:37 +0000
commit970d4132b66eb77fa0c3d1d2626a1e377bea6ad4 (patch)
tree1ca314de18a1436b1d62f1814fa5f3f70a0ec357 /src/compiler/scala/tools/nsc
parent44b9cf0ca9606f531218deefe7792b4476552291 (diff)
downloadscala-970d4132b66eb77fa0c3d1d2626a1e377bea6ad4.tar.gz
scala-970d4132b66eb77fa0c3d1d2626a1e377bea6ad4.tar.bz2
scala-970d4132b66eb77fa0c3d1d2626a1e377bea6ad4.zip
Refactored infoTransformer functionality from n...
Refactored infoTransformer functionality from nsc.transform to reflect.internal.transform. Needed so that we can find Java methods that correspond to Scala methods. Review by extempore.
Diffstat (limited to 'src/compiler/scala/tools/nsc')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala260
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala63
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala14
4 files changed, 19 insertions, 320 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 837796e261..c4a728a091 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -12,6 +12,7 @@ import symtab._
import Flags._
abstract class Erasure extends AddInterfaces
+ with reflect.internal.transform.Erasure
with typechecker.Analyzer
with TypingTransformers
with ast.TreeDSL
@@ -29,43 +30,6 @@ abstract class Erasure extends AddInterfaces
// -------- erasure on types --------------------------------------------------------
- /** An extractor object for generic arrays */
- object GenericArray {
-
- /** Is `tp` an unbounded generic type (i.e. which could be instantiated
- * with primitive as well as class types)?.
- */
- private def genericCore(tp: Type): Type = tp.normalize match {
- case TypeRef(_, sym, _) if sym.isAbstractType && !sym.owner.isJavaDefined =>
- tp
- case ExistentialType(tparams, restp) =>
- genericCore(restp)
- case _ =>
- NoType
- }
-
- /** If `tp` is of the form Array[...Array[T]...] where `T` is an abstract type
- * then Some(N, T) where N is the number of Array constructors enclosing `T`,
- * otherwise None. Existentials on any level are ignored.
- */
- def unapply(tp: Type): Option[(Int, Type)] = tp.normalize match {
- case TypeRef(_, ArrayClass, List(arg)) =>
- genericCore(arg) match {
- case NoType =>
- unapply(arg) match {
- case Some((level, core)) => Some((level + 1, core))
- case None => None
- }
- case core =>
- Some(1, core)
- }
- case ExistentialType(tparams, restp) =>
- unapply(restp)
- case _ =>
- None
- }
- }
-
// A type function from T => Class[U], used to determine the return
// type of getClass calls. The returned type is:
//
@@ -108,170 +72,6 @@ abstract class Erasure extends AddInterfaces
atPos(tree.pos)(Apply(Select(tree, conversion), Nil))
}
- private def unboundedGenericArrayLevel(tp: Type): Int = tp match {
- case GenericArray(level, core) if !(core <:< AnyRefClass.tpe) => level
- case _ => 0
- }
-
- // @M #2585 when generating a java generic signature that includes a selection of an inner class p.I, (p = `pre`, I = `cls`)
- // must rewrite to p'.I, where p' refers to the class that directly defines the nested class I
- // see also #2585 marker in javaSig: there, type arguments must be included (use pre.baseType(cls.owner))
- // requires cls.isClass
- @inline private def rebindInnerClass(pre: Type, cls: Symbol): Type =
- if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass?
-
- /** The erasure |T| of a type T. This is:
- *
- * - For a constant type, itself.
- * - For a type-bounds structure, the erasure of its upper bound.
- * - For every other singleton type, the erasure of its supertype.
- * - For a typeref scala.Array+[T] where T is an abstract type, AnyRef.
- * - For a typeref scala.Array+[T] where T is not an abstract type, scala.Array+[|T|].
- * - For a typeref scala.Any or scala.AnyVal, java.lang.Object.
- * - For a typeref scala.Unit, scala.runtime.BoxedUnit.
- * - For a typeref P.C[Ts] where C refers to a class, |P|.C.
- * (Where P is first rebound to the class that directly defines C.)
- * - For a typeref P.C[Ts] where C refers to an alias type, the erasure of C's alias.
- * - For a typeref P.C[Ts] where C refers to an abstract type, the
- * erasure of C's upper bound.
- * - For a non-empty type intersection (possibly with refinement)
- * - in scala, the erasure of the intersection dominator
- * - in java, the erasure of its first parent <--- @PP: not yet in spec.
- * - For an empty type intersection, java.lang.Object.
- * - For a method type (Fs)scala.Unit, (|Fs|)scala#Unit.
- * - For any other method type (Fs)Y, (|Fs|)|T|.
- * - For a polymorphic type, the erasure of its result type.
- * - For the class info type of java.lang.Object, the same type without any parents.
- * - For a class info type of a value class, the same type without any parents.
- * - For any other class info type with parents Ps, the same type with
- * parents |Ps|, but with duplicate references of Object removed.
- * - for all other types, the type itself (with any sub-components erased)
- */
- def erasure(sym: Symbol, tp: Type): Type = {
- if (sym != NoSymbol && sym.enclClass.isJavaDefined) {
- val res = javaErasure(tp)
- if (verifyJavaErasure && sym.isMethod) {
- val old = scalaErasure(tp)
- if (!(res =:= old))
- log("Identified divergence between java/scala erasure:\n scala: " + old + "\n java: " + res)
- }
- res
- }
- else scalaErasure(tp)
- }
-
- /** Scala's more precise erasure than java's is problematic as follows:
- *
- * - Symbols are read from classfiles and populated with types
- * - The textual signature read from the bytecode is forgotten
- * - Bytecode generation must know the precise signature of a method
- * - the signature is derived from the erasure of the method type
- * - If that derivation does not adhere to the rules by which the original
- * signature was created, a NoSuchMethod error will result.
- *
- * For this reason and others (such as distinguishing constructors from other methods)
- * erasure is now (Symbol, Type) => Type rather than Type => Type.
- */
- object scalaErasure extends ErasureMap {
- /** In scala, calculate a useful parent.
- * An intersection such as `Object with Trait` erases to Trait.
- */
- def mergeParents(parents: List[Type]): Type =
- intersectionDominator(parents)
- }
- object javaErasure extends ErasureMap {
- /** In java, always take the first parent.
- * An intersection such as `Object with Trait` erases to Object.
- */
- def mergeParents(parents: List[Type]): Type =
- if (parents.isEmpty) ObjectClass.tpe
- else parents.head
- }
-
- /** The intersection dominator (SLS 3.7) of a list of types is computed as follows.
- *
- * - If the list contains one or more occurrences of scala.Array with
- * type parameters El1, El2, ... then the dominator is scala.Array with
- * type parameter of intersectionDominator(List(El1, El2, ...)). <--- @PP: not yet in spec.
- * - Otherwise, the list is reduced to a subsequence containing only types
- * which are not subtypes of other listed types (the span.)
- * - If the span is empty, the dominator is Object.
- * - If the span contains a class Tc which is not a trait and which is
- * not Object, the dominator is Tc. <--- @PP: "which is not Object" not in spec.
- * - Otherwise, the dominator is the first element of the span.
- */
- def intersectionDominator(parents: List[Type]): Type = {
- if (parents.isEmpty) ObjectClass.tpe
- else {
- val psyms = parents map (_.typeSymbol)
- if (psyms contains ArrayClass) {
- // treat arrays specially
- arrayType(
- intersectionDominator(
- parents filter (_.typeSymbol == ArrayClass) map (_.typeArgs.head)))
- } else {
- // implement new spec for erasure of refined types.
- def isUnshadowed(psym: Symbol) =
- !(psyms exists (qsym => (psym ne qsym) && (qsym isNonBottomSubClass psym)))
- val cs = parents.iterator.filter { p => // isUnshadowed is a bit expensive, so try classes first
- val psym = p.typeSymbol
- psym.initialize
- psym.isClass && !psym.isTrait && isUnshadowed(psym)
- }
- (if (cs.hasNext) cs else parents.iterator.filter(p => isUnshadowed(p.typeSymbol))).next()
- }
- }
- }
-
- abstract class ErasureMap extends TypeMap {
- def mergeParents(parents: List[Type]): Type
-
- def apply(tp: Type): Type = {
- tp match {
- case ConstantType(_) =>
- tp
- case st: SubType =>
- apply(st.supertype)
- case TypeRef(pre, sym, args) =>
- if (sym == ArrayClass)
- if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe
- else if (args.head.typeSymbol == NothingClass || args.head.typeSymbol == NullClass) arrayType(ObjectClass.tpe)
- else typeRef(apply(pre), sym, args map this)
- else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass)
- else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
- else if (sym.isRefinementClass) apply(mergeParents(tp.parents))
- else if (sym.isClass) typeRef(apply(rebindInnerClass(pre, sym)), sym, List()) // #2585
- else apply(sym.info) // alias type or abstract type
- case PolyType(tparams, restpe) =>
- apply(restpe)
- case ExistentialType(tparams, restpe) =>
- apply(restpe)
- case mt @ MethodType(params, restpe) =>
- MethodType(
- cloneSymbols(params) map (p => p.setInfo(apply(p.tpe))),
- if (restpe.typeSymbol == UnitClass)
- erasedTypeRef(UnitClass)
- else if (settings.YdepMethTpes.value)
- // this replaces each typeref that refers to an argument
- // by the type `p.tpe` of the actual argument p (p in params)
- apply(mt.resultType(params map (_.tpe)))
- else
- apply(restpe))
- case RefinedType(parents, decls) =>
- apply(mergeParents(parents))
- case AnnotatedType(_, atp, _) =>
- apply(atp)
- case ClassInfoType(parents, decls, clazz) =>
- ClassInfoType(
- if (clazz == ObjectClass || isValueClass(clazz)) Nil
- else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass))
- else removeDoubleObject(parents map this),
- decls, clazz)
- case _ =>
- mapOver(tp)
- }
- }
- }
private object NeedsSigCollector extends TypeCollector(false) {
def traverse(tp: Type) {
@@ -299,7 +99,7 @@ abstract class Erasure extends AddInterfaces
}
}
- private def verifyJavaErasure = settings.Xverify.value || settings.debug.value
+ override protected def verifyJavaErasure = settings.Xverify.value || settings.debug.value
private def needsJavaSig(tp: Type) = !settings.Ynogenericsig.value && NeedsSigCollector.collect(tp)
// only refer to type params that will actually make it into the sig, this excludes:
@@ -521,18 +321,6 @@ abstract class Erasure extends AddInterfaces
class UnknownSig extends Exception
- /** Type reference after erasure */
- def erasedTypeRef(sym: Symbol): Type =
- typeRef(erasure(sym, sym.owner.tpe), sym, List())
-
- /** Remove duplicate references to class Object in a list of parent classes */
- private def removeDoubleObject(tps: List[Type]): List[Type] = tps match {
- case List() => List()
- case tp :: tps1 =>
- if (tp.typeSymbol == ObjectClass) tp :: tps1.filter(_.typeSymbol != ObjectClass)
- else tp :: removeDoubleObject(tps1)
- }
-
/** The symbol's erased info. This is the type's erasure, except for the following symbols:
*
* - For $asInstanceOf : [T]T
@@ -541,48 +329,8 @@ abstract class Erasure extends AddInterfaces
* - For Array[T].<init> : {scala#Int)Array[T]
* - For a type parameter : A type bounds type consisting of the erasures of its bounds.
*/
- def transformInfo(sym: Symbol, tp: Type): Type = {
- if (sym == Object_asInstanceOf)
- sym.info
- else if (sym == Object_isInstanceOf || sym == ArrayClass)
- PolyType(sym.info.typeParams, erasure(sym, sym.info.resultType))
- else if (sym.isAbstractType)
- TypeBounds(WildcardType, WildcardType)
- else if (sym.isTerm && sym.owner == ArrayClass) {
- if (sym.isClassConstructor)
- tp match {
- case MethodType(params, TypeRef(pre, sym1, args)) =>
- MethodType(cloneSymbols(params) map (p => p.setInfo(erasure(sym, p.tpe))),
- typeRef(erasure(sym, pre), sym1, args))
- }
- else if (sym.name == nme.apply)
- tp
- else if (sym.name == nme.update)
- (tp: @unchecked) match {
- case MethodType(List(index, tvar), restpe) =>
- MethodType(List(index.cloneSymbol.setInfo(erasure(sym, index.tpe)), tvar),
- erasedTypeRef(UnitClass))
- }
- else erasure(sym, tp)
- } else if (
- sym.owner != NoSymbol &&
- sym.owner.owner == ArrayClass &&
- sym == Array_update.paramss.head(1)) {
- // special case for Array.update: the non-erased type remains, i.e. (Int,A)Unit
- // since the erasure type map gets applied to every symbol, we have to catch the
- // symbol here
- tp
- } else {
-/*
- val erased =
- if (sym.isGetter && sym.tpe.isInstanceOf[MethodType])
- erasure mapOver sym.tpe // for getters, unlike for normal methods, always convert Unit to BoxedUnit.
- else
- erasure(tp)
-*/
- transformMixinInfo(erasure(sym, tp))
- }
- }
+ override def transformInfo(sym: Symbol, tp: Type): Type =
+ transformMixinInfo(super.transformInfo(sym, tp))
val deconstMap = new TypeMap {
// For some reason classOf[Foo] creates ConstantType(Constant(tpe)) with an actual Type for tpe,
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index f2e4495783..992a746e1e 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -123,6 +123,8 @@ abstract class ExplicitOuter extends InfoTransform
* Remove protected flag from all members of traits.
* </li>
* </ol>
+ * Note: this transformInfo need not be reflected as the JVM reflection already
+ * elides outer pointers.
*/
def transformInfo(sym: Symbol, tp: Type): Type = tp match {
case MethodType(params, restpe1) =>
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 0916cf989d..bd9f24177a 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -34,7 +34,11 @@ import scala.collection.{ mutable, immutable }
* - convert non-local returns to throws with enclosing try statements.
*/
/*</export> */
-abstract class UnCurry extends InfoTransform with TypingTransformers with ast.TreeDSL {
+abstract class UnCurry extends InfoTransform
+ with reflect.internal.transform.UnCurry
+ with TypingTransformers with ast.TreeDSL {
+ val global: Global // need to repeat here because otherwise last mixin defines global as
+ // SymbolTable. If we had DOT this would not be an issue
import global._ // the global environment
import definitions._ // standard classes and methods
import CODE._
@@ -47,63 +51,6 @@ abstract class UnCurry extends InfoTransform with TypingTransformers with ast.Tr
// ------ Type transformation --------------------------------------------------------
// uncurry and uncurryType expand type aliases
- private def expandAlias(tp: Type): Type = if (!tp.isHigherKinded) tp.normalize else tp
-
- private def isUnboundedGeneric(tp: Type) = tp match {
- case t @ TypeRef(_, sym, _) => sym.isAbstractType && !(t <:< AnyRefClass.tpe)
- case _ => false
- }
-
- private val uncurry: TypeMap = new TypeMap {
- def apply(tp0: Type): Type = {
- // tp0.typeSymbolDirect.initialize
- val tp = expandAlias(tp0)
- tp match {
- case MethodType(params, MethodType(params1, restpe)) =>
- apply(MethodType(params ::: params1, restpe))
- case MethodType(params, ExistentialType(tparams, restpe @ MethodType(_, _))) =>
- assert(false, "unexpected curried method types with intervening existential")
- tp0
- case MethodType(h :: t, restpe) if h.isImplicit =>
- apply(MethodType(h.cloneSymbol.resetFlag(IMPLICIT) :: t, restpe))
- case NullaryMethodType(restpe) =>
- apply(MethodType(List(), restpe))
- case TypeRef(pre, ByNameParamClass, List(arg)) =>
- apply(functionType(List(), arg))
- case TypeRef(pre, RepeatedParamClass, args) =>
- apply(appliedType(SeqClass.typeConstructor, args))
- case TypeRef(pre, JavaRepeatedParamClass, args) =>
- apply(arrayType(
- if (isUnboundedGeneric(args.head)) ObjectClass.tpe else args.head))
- case _ =>
- expandAlias(mapOver(tp))
- }
- }
- }
-
- private val uncurryType = new TypeMap {
- def apply(tp0: Type): Type = {
- val tp = expandAlias(tp0)
- tp match {
- case ClassInfoType(parents, decls, clazz) =>
- val parents1 = parents mapConserve uncurry
- if (parents1 eq parents) tp
- else ClassInfoType(parents1, decls, clazz) // @MAT normalize in decls??
- case PolyType(_, _) =>
- mapOver(tp)
- case _ =>
- tp
- }
- }
- }
-
- /** - return symbol's transformed type,
- * - if symbol is a def parameter with transformed type T, return () => T
- *
- * @MAT: starting with this phase, the info of every symbol will be normalized
- */
- def transformInfo(sym: Symbol, tp: Type): Type =
- if (sym.isType) uncurryType(tp) else uncurry(tp)
/** Traverse tree omitting local method definitions.
* If a `return` is encountered, set `returnFound` to true.
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index bf6e7a91ba..8e1ee97387 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -37,7 +37,10 @@ import scala.collection.mutable.ListBuffer
*
* @todo Check whether we always check type parameter bounds.
*/
-abstract class RefChecks extends InfoTransform {
+abstract class RefChecks extends InfoTransform with reflect.internal.transform.RefChecks {
+
+ val global: Global // need to repeat here because otherwise last mixin defines global as
+ // SymbolTable. If we had DOT this would not be an issue
import global._
import definitions._
@@ -51,11 +54,10 @@ abstract class RefChecks extends InfoTransform {
new RefCheckTransformer(unit)
override def changesBaseClasses = false
- def transformInfo(sym: Symbol, tp: Type): Type =
- if (sym.isModule && !sym.isStatic) {
- sym setFlag (lateMETHOD | STABLE)
- NullaryMethodType(tp)
- } else tp
+ override def transformInfo(sym: Symbol, tp: Type): Type = {
+ if (sym.isModule && !sym.isStatic) sym setFlag (lateMETHOD | STABLE)
+ super.transformInfo(sym, tp)
+ }
val toJavaRepeatedParam = new TypeMap {
def apply(tp: Type) = tp match {