diff options
author | Paul Phillips <paulp@improving.org> | 2011-06-21 04:29:22 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-06-21 04:29:22 +0000 |
commit | 7d5b6fa1eefd098b4d08927b5a40497f4bb9c132 (patch) | |
tree | a42b883ff2cb87781019a20e47a9ee1ad2d39068 /src | |
parent | cf85a61beb205aea4f177ef569e6d219c667c894 (diff) | |
download | scala-7d5b6fa1eefd098b4d08927b5a40497f4bb9c132.tar.gz scala-7d5b6fa1eefd098b4d08927b5a40497f4bb9c132.tar.bz2 scala-7d5b6fa1eefd098b4d08927b5a40497f4bb9c132.zip |
Performance-motivated work: going through Speci...
Performance-motivated work: going through SpecializeTypes and
eliminating unnecessary intermediate data structures and multiple
traversals of lists. Also trying to get that code under control: it
dwarfs all other phases in terms of debugging output, and a too-large
percentage of the source is commented out debugging code which looks
past its sell-by date. I realize the patch is a little big for a very
thorough review, but review by dragos, prokopec.
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/reflect/internal/Definitions.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala | 1022 |
2 files changed, 460 insertions, 563 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 5201ad2fe0..967bea38b4 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -732,6 +732,7 @@ trait Definitions /*extends reflect.generic.StandardDefinitions*/ { /** Is symbol a value class? */ def isValueClass(sym: Symbol) = scalaValueClassesSet(sym) def isNonUnitValueClass(sym: Symbol) = (sym != UnitClass) && isValueClass(sym) + def isScalaValueType(tp: Type) = scalaValueClassesSet(tp.typeSymbol) /** Is symbol a boxed value class, e.g. java.lang.Integer? */ def isBoxedValueClass(sym: Symbol) = boxedValueClassesSet(sym) diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 487716c457..e6fb738dbb 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -21,28 +21,44 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { override def changesBaseClasses = true override def keepsTypeParams = true - /** Concrete types for specialization */ -// final lazy val concreteTypes = List(definitions.IntClass.tpe, definitions.DoubleClass.tpe) - type TypeEnv = immutable.Map[Symbol, Type] - def emptyEnv: TypeEnv = immutable.ListMap.empty[Symbol, Type] + def emptyEnv: TypeEnv = Map[Symbol, Type]() + private implicit val typeOrdering: Ordering[Type] = Ordering[String] on ("" + _.typeSymbol.name) import definitions.{ - RootClass, BooleanClass, UnitClass, ArrayClass, ScalaValueClasses, + RootClass, BooleanClass, UnitClass, ArrayClass, + ScalaValueClasses, isValueClass, isScalaValueType, SpecializedClass, RepeatedParamClass, JavaRepeatedParamClass, - AnyRefClass, Predef_AnyRef, ObjectClass, - isValueClass + AnyRefClass, ObjectClass, Predef_AnyRef, + uncheckedVarianceClass + } + private def isSpecialized(sym: Symbol) = sym hasAnnotation SpecializedClass + private def hasSpecializedFlag(sym: Symbol) = sym hasFlag SPECIALIZED + private def specializedTypes(tps: List[Symbol]) = tps filter isSpecialized + private def specializedOn(sym: Symbol) = sym getAnnotation SpecializedClass match { + case Some(AnnotationInfo(_, args, _)) => args + case _ => Nil } - private def isSpecialized(sym: Symbol) = sym hasAnnotation SpecializedClass - private def isSpecializedOnAnyRef(sym: Symbol) = sym.getAnnotation(SpecializedClass) match { - case Some(AnnotationInfo(_, args, _)) => args.exists(_.symbol == Predef_AnyRef) - case _ => false + // If we replace `isBoundedGeneric` with (tp <:< AnyRefClass.tpe), + // then pos/spec-List.scala fails - why? Does this kind of check fail + // for similar reasons? Does `sym.isAbstractType` make a difference? + private def isSpecializedAnyRefSubtype(tp: Type, sym: Symbol) = ( + specializedOn(sym).exists(_.symbol == Predef_AnyRef) // specialized on AnyRef + && !isValueClass(tp.typeSymbol) + && isBoundedGeneric(tp) + ) + private def isBoundedGeneric(tp: Type) = tp match { + case TypeRef(_, sym, _) if sym.isAbstractType => (tp <:< AnyRefClass.tpe) + case TypeRef(_, sym, _) => !isValueClass(sym) + case _ => false } - private def specializedOn(sym: Symbol) = sym.getAnnotation(SpecializedClass) match { - case Some(AnnotationInfo(_, args, _)) => args - case _ => Nil + @inline private def debuglog(msg: => String) { + if (settings.debug.value) log(msg) + } + @inline private def ifDebug(body: => Unit) { + if (settings.debug.value) { body } } object TypeEnv { @@ -50,7 +66,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * the given args. Expects the lists to have the same length. */ def fromSpecialization(sym: Symbol, args: List[Type]): TypeEnv = { - assert(sym.info.typeParams.length == args.length, sym + " args: " + args) + ifDebug(assert(sym.info.typeParams.length == args.length, sym + " args: " + args)) + emptyEnv ++ (sym.info.typeParams zip args filter (kv => isSpecialized(kv._1))) } @@ -61,14 +78,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ def includes(t1: TypeEnv, t2: TypeEnv) = t1 forall { case (sym, tpe) => - val t2tpopt = t2 get sym - // log("includes: " + t2tpopt.map(_.getClass)) - // log(tpe.getClass) - t2tpopt match { - case Some(t2tp) => t2tp == tpe || { - (!primitiveTypes.contains(tpe)) && (!isValueClass(t2tp.typeSymbol)) // u.t.b. (t2tp <:< AnyRefClass.tpe) - } - case None => false + t2 get sym exists { t2tp => + (tpe == t2tp) || !(isScalaValueType(tpe) || isScalaValueType(t2tp)) // u.t.b. (t2tp <:< AnyRefClass.tpe) } } @@ -81,21 +92,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * to a type for which `sym` is specialized. */ def isValid(env: TypeEnv, sym: Symbol): Boolean = { - def validBinding(tvar: Symbol, tpe: Type, sym: Symbol) = ( - isSpecialized(tvar) - && sym.typeParams.contains(tvar) - && concreteTypes(tvar).contains(tpe) - ) - env forall { - case (tvar, tpe) => -// log("isValid: " + env + " sym: " + sym + " sym.tparams: " + sym.typeParams) -// log("Flag " + tvar + ": " + tvar.hasAnnotation(SpecializedClass)) -// log("tparams contains: " + sym.typeParams.contains(tvar)) -// log("concreteTypes: " + concreteTypes.contains(tpe)) - - validBinding(tvar, tpe, sym) || ( - (sym.owner != RootClass) && validBinding(tvar, tpe, sym.owner) - ) + env forall { case (tvar, tpe) => + isSpecialized(tvar) && (concreteTypes(tvar) contains tpe) && { + (sym.typeParams contains tvar) || + (sym.owner != RootClass && (sym.owner.typeParams contains tvar)) + } } } } @@ -107,22 +108,19 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * 'cls' itself if cls is not a specialized subclass. */ def genericClass(cls: Symbol): Symbol = - if (cls.hasFlag(SPECIALIZED)) - cls.info.parents.head.typeSymbol - else - cls + if (hasSpecializedFlag(cls)) cls.info.parents.head.typeSymbol + else cls /** Map a method symbol to a list of its specialized overloads in the same class. */ - private val overloads: mutable.Map[Symbol, List[Overload]] = new mutable.HashMap[Symbol, List[Overload]] { - override def default(key: Symbol): List[Overload] = Nil - } + private val overloads: mutable.Map[Symbol, List[Overload]] = + new mutable.HashMap[Symbol, List[Overload]] { + override def default(key: Symbol): List[Overload] = Nil + } case class Overload(sym: Symbol, env: TypeEnv) { - override def toString: String = - "specialized overload " + sym + " in " + env + override def toString = "specialized overload " + sym + " in " + env } - /** Just to mark uncheckable */ override def newPhase(prev: scala.tools.nsc.Phase): StdPhase = new SpecializationPhase(prev) class SpecializationPhase(prev: scala.tools.nsc.Phase) extends super.Phase(prev) { @@ -181,11 +179,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } override lazy val degenerate = { - log("degenerate: " + target + - " stv tparams: " + specializedTypeVars(target.info.typeParams map (_.info)) + - " stv info: " + specializedTypeVars(target.info.resultType)) - !(specializedTypeVars(target.info.typeParams map (_.info)) - -- specializedTypeVars(target.info.resultType)).isEmpty + val stvTypeParams = specializedTypeVars(target.info.typeParams map (_.info)) + val stvResult = specializedTypeVars(target.info.resultType) + + log("degenerate: " + target + " stv tparams: " + stvTypeParams + " stv info: " + stvResult) + + (stvTypeParams -- stvResult).nonEmpty } } @@ -193,12 +192,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { private val info: mutable.Map[Symbol, SpecializedInfo] = new mutable.HashMap[Symbol, SpecializedInfo] /** Has `clazz` any type parameters that need be specialized? */ - def hasSpecializedParams(clazz: Symbol): Boolean = - !specializedParams(clazz).isEmpty + def hasSpecializedParams(clazz: Symbol) = + clazz.info.typeParams exists isSpecialized /** Return specialized type parameters. */ def specializedParams(sym: Symbol): List[Symbol] = - splitParams(sym.info.typeParams)._1 + sym.info.typeParams filter isSpecialized def splitParams(tps: List[Symbol]) = tps partition isSpecialized @@ -208,49 +207,24 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * specialized type. */ def survivingArgs(sym: Symbol, args: List[Type]): List[Type] = - for ((tvar, tpe) <- sym.info.typeParams.zip(args) if !isSpecialized(tvar) || !isPrimitive(tpe)) + for ((tvar, tpe) <- sym.info.typeParams.zip(args) if !isSpecialized(tvar) || !isScalaValueType(tpe)) yield tpe - private def isBoundedGeneric(tp: Type) = tp match { - case TypeRef(_, sym, _) if sym.isAbstractType => (tp <:< AnyRefClass.tpe) - case TypeRef(_, sym, _) => !isValueClass(sym) - case _ => false - } - - private def str(tp: Type): AnyRef = tp match { - case TypeRef(pre, sym, args) => (str(pre), sym, args) - case _ => "nontpref sym: " + tp.typeSymbol + ", " + tp.getClass - } - - // If we replace `isBoundedGeneric` with (tp <:< AnyRefClass.tpe), then pos/spec-List.scala fails - why? - // Does this kind of check fail for similar reasons? Does `sym.isAbstractType` make a difference? - private def subtypeOfAnyRef(tp: Type) = { - // log(tp + " <:< AnyRef? tp has symbol: " + tp.typeSymbol + ", " + tp.typeSymbol.ownerChain) - !isValueClass(tp.typeSymbol) && isBoundedGeneric(tp) - } - val specializedType = new TypeMap { override def apply(tp: Type): Type = tp match { case TypeRef(pre, sym, args) if args.nonEmpty => val pre1 = this(pre) // when searching for a specialized class, take care to map all // type parameters that are subtypes of AnyRef to AnyRef - // log("Mapping " + args.map(_.typeSymbol) + ", from " + sym + " with params " + sym.typeParams + " with annots " + sym.typeParams.map(_.annotations)) val args1 = (args zip sym.typeParams) map { - case (x, orig) if isSpecializedOnAnyRef(orig) && subtypeOfAnyRef(x) => AnyRefClass.tpe // used to be: case x if x <:< AnyRefClass.tpe - case (x, _) => x + case (tp, orig) if isSpecializedAnyRefSubtype(tp, orig) => AnyRefClass.tpe + case (tp, _) => tp } - // log("!!! specializedType " + tp + ", " + pre1 + ", " + args1) specializedClass.get((sym, TypeEnv.fromSpecialization(sym, args1))) match { - case Some(sym1) => - val surviving = survivingArgs(sym, args) - // log("!!! survivers: " + surviving) - assert(sym1.info.typeParams.length == surviving.length, sym1) - typeRef(pre1, sym1, surviving) - case None => - typeRef(pre1, sym, args) + case Some(sym1) => typeRef(pre1, sym1, survivingArgs(sym, args)) + case None => typeRef(pre1, sym, args) } - case _ => tp // mapOver(tp) + case _ => tp } } @@ -263,13 +237,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * type variables alphabetically. */ private def specializedName(sym: Symbol, env: TypeEnv): TermName = { - val tvars = if (sym.isClass) env.keySet - else specializedTypeVars(sym).intersect(env.keySet) - val (methparams, others) = tvars.toList.partition(_.owner.isMethod) - val tvars1 = methparams sortBy (_.name.toString) - val tvars2 = others sortBy (_.name.toString) - if (settings.debug.value) log("specName(%s) env: %s tvars: %s ".format(sym, env, (tvars1, tvars2))) - specializedName(sym.name, tvars1 map env, tvars2 map env) + val tvars = ( + if (sym.isClass) env.keySet + else specializedTypeVars(sym).intersect(env.keySet) + ) + val (methparams, others) = tvars.toList sortBy ("" + _.name) partition (_.owner.isMethod) + debuglog("specName(" + sym + ") env: " + env + " tvars: " + tvars) + + specializedName(sym.name, methparams map env, others map env) } /** Specialize name for the two list of types. The first one denotes @@ -296,46 +271,38 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Return the types `sym` should be specialized at. This may be some of the primitive types * or AnyRef. AnyRef means that a new type parameter T will be generated later, known to be a * subtype of AnyRef (T <: AnyRef). + * These are in a meaningful order for stability purposes. */ - def concreteTypes(sym: Symbol): List[Type] = { - sym.getAnnotation(SpecializedClass) match { - case Some(AnnotationInfo(_, args, _)) => - args match { - case Nil => - log(sym + " specialized on everything") - primitiveTypes - case _ => - val tpes = args map { - t => if (t.symbol == Predef_AnyRef) { - if (isBoundedGeneric(sym.tpe)) - reporter.warning(sym.pos, sym + " is always a subtype of " + AnyRefClass.tpe + ".") - AnyRefClass.tpe - } else t.symbol.companionClass.tpe - } - log(sym + " specialized on " + tpes) - tpes - } - case _ => - Nil + def concreteTypes(sym: Symbol): List[Type] = ( + if (!isSpecialized(sym)) Nil // no @specialized Annotation + else specializedOn(sym) match { + case Nil => primitiveTypes // specialized on everything + case args => // specialized on args + (args map { tp => + if (tp.symbol == Predef_AnyRef) { + if (isBoundedGeneric(sym.tpe)) + reporter.warning(sym.pos, sym + " is always a subtype of " + AnyRefClass.tpe + ".") + AnyRefClass.tpe + } + else tp.symbol.companionClass.tpe + }).sorted } - } + ) /** Return a list of all type environments for all specializations * of @specialized types in `tps`. */ private def specializations(tps: List[Symbol]): List[TypeEnv] = { - val stps = tps filter isSpecialized - count(stps, concreteTypes _) map (tps => immutable.HashMap(stps zip tps: _*)) - } - - /** Generate all arrangements with repetitions from the list of values, - * with 'pos' positions. For example, count(2, List(1, 2)) yields - * List(List(1, 1), List(1, 2), List(2, 1), List(2, 2)) - */ - private def count[A, V](xs: List[A], values: A => List[V]): List[List[V]] = { - if (xs.isEmpty) Nil - else if (xs.tail.isEmpty) values(xs.head) map (_ :: Nil) - else for (v <- values(xs.head); vs <- count(xs.tail, values)) yield v :: vs + // the keys in each TypeEnv + val keys: List[Symbol] = tps filter isSpecialized + // creating each permutation of concrete types + def loop(ctypes: List[List[Type]]): List[List[Type]] = ctypes match { + case Nil => Nil + case set :: Nil => set map (x => List(x)) + case set :: sets => for (x <- set ; xs <- loop(sets)) yield x :: xs + } + // zip the keys with each permutation to create a TypeEnv + loop(keys map concreteTypes) map (keys zip _ toMap) } /** Does the given tpe need to be specialized in the environment 'env'? @@ -350,18 +317,15 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { (isNormalizedMember(sym) && info(sym).typeBoundsIn(env)) } - def isNormalizedMember(m: Symbol): Boolean = - (m.hasFlag(SPECIALIZED) && (info.get(m) match { - case Some(NormalizedMember(_)) => true - case _ => false - })) - - - def specializedTypeVars(tpe: List[Type]): immutable.Set[Symbol] = - tpe.foldLeft(immutable.ListSet.empty[Symbol]: immutable.Set[Symbol]) { - (s, tp) => s ++ specializedTypeVars(tp) - } - + def isNormalizedMember(m: Symbol) = hasSpecializedFlag(m) && (info get m exists { + case NormalizedMember(_) => true + case _ => false + }) + def specializedTypeVars(tpes: List[Type]): immutable.Set[Symbol] = { + val buf = Set.newBuilder[Symbol] + tpes foreach (tp => buf ++= specializedTypeVars(tp)) + buf.result + } def specializedTypeVars(sym: Symbol): immutable.Set[Symbol] = atPhase(currentRun.typerPhase)(specializedTypeVars(sym.info)) @@ -375,70 +339,57 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case TypeRef(pre, sym, args) => if (sym.isAliasType) specializedTypeVars(tpe.normalize) - else if (sym.isTypeParameter && isSpecialized(sym) - || (sym.isTypeSkolem && isSpecialized(sym.deSkolemize))) - immutable.ListSet.empty + sym + else if (sym.isTypeParameter && isSpecialized(sym) || (sym.isTypeSkolem && isSpecialized(sym.deSkolemize))) + Set(sym) else if (sym == ArrayClass) specializedTypeVars(args) - else { - val extra = for ((tp, arg) <- sym.typeParams.zip(args) if isSpecialized(tp)) - yield specializedTypeVars(arg).toList - immutable.ListSet.empty[Symbol] ++ extra.flatten - } - - case PolyType(tparams, resTpe) => - specializedTypeVars(tparams map (_.info)) ++ specializedTypeVars(resTpe) - - case NullaryMethodType(resTpe) => // since this method may be run at phase typer (before uncurry, where NMTs are eliminated) - specializedTypeVars(resTpe) - case MethodType(argSyms, resTpe) => - specializedTypeVars(argSyms map (_.tpe)) ++ specializedTypeVars(resTpe) - - case ExistentialType(_, res) => specializedTypeVars(res) - case AnnotatedType(_, tp, _) => specializedTypeVars(tp) - case TypeBounds(lo, hi) => specializedTypeVars(lo) ++ specializedTypeVars(hi) - case _ => immutable.ListSet.empty[Symbol] + else + specializedTypeVars(sym.typeParams zip args collect { case (tp, arg) if isSpecialized(tp) => arg }) + + case PolyType(tparams, resTpe) => specializedTypeVars(resTpe :: tparams.map(_.info)) + // since this method may be run at phase typer (before uncurry, where NMTs are eliminated) + case NullaryMethodType(resTpe) => specializedTypeVars(resTpe) + case MethodType(argSyms, resTpe) => specializedTypeVars(resTpe :: argSyms.map(_.tpe)) + case ExistentialType(_, res) => specializedTypeVars(res) + case AnnotatedType(_, tp, _) => specializedTypeVars(tp) + case TypeBounds(lo, hi) => specializedTypeVars(List(lo, hi)) + case _ => Set() } - // holds mappings from regular type parameter symbols to symbols of specialized type parameters - // which are subtypes of AnyRef + // holds mappings from regular type parameter symbols to symbols of + // specialized type parameters which are subtypes of AnyRef private val anyrefSpecCache = mutable.Map[Symbol, Symbol]() + /** Returns the type parameter in the specialized class `cls` that corresponds to type parameter * `sym` in the original class. It will create it if needed or use the one from the cache. */ - private def typeParamSubAnyRef(sym: Symbol, cls: Symbol) = anyrefSpecCache.get(sym) match { - case Some(tsub) => tsub.tpe - case None => - val tparam = cls.newTypeParameter(sym.pos, newTypeName(sym.name.toString + "$sp")) - tparam.setInfo(TypeBounds(sym.info.bounds.lo, AnyRefClass.tpe)) - anyrefSpecCache.put(sym, tparam) - tparam.tpe - } - - /** Cleans the anyrefSpecCache of all type parameter symbols of a class */ - private def cleanAnyRefSpecCache(cls: Symbol, decls: List[Symbol]) = { - // remove class type parameters - cls.tpe match { - case PolyType(tparams, _) => for (tp <- tparams) anyrefSpecCache.remove(tp) - case _ => - } - - // remove mappings from normalized members to - for (d <- decls) d.tpe match { - case PolyType(tparams, _) => for (tp <- tparams) anyrefSpecCache.remove(tp) - case _ => + private def typeParamSubAnyRef(sym: Symbol, cls: Symbol) = ( + anyrefSpecCache.getOrElseUpdate(sym, + cls.newTypeParameter(sym.pos, newTypeName(sym.name + "$sp")) + setInfo TypeBounds(sym.info.bounds.lo, AnyRefClass.tpe) + ).tpe + ) + + /** Cleans the anyrefSpecCache of all type parameter symbols of a class. + */ + private def cleanAnyRefSpecCache(cls: Symbol, decls: List[Symbol]) = ( + // remove class type parameters and those of normalized members. + cls :: decls foreach { + _.tpe match { + case PolyType(tparams, _) => anyrefSpecCache --= tparams + case _ => () + } } - } + ) // holds mappings from members to the type variables in the class that they were already specialized for, // so that they don't get specialized twice (this is for AnyRef specializations) - private val wasSpecializedForTypeVars = mutable.Map[Symbol, immutable.Set[Symbol]]() withDefaultValue immutable.Set[Symbol]() - - def isPrimitive(tpe: Type) = primitiveTypes contains tpe + private val wasSpecializedForTypeVars = + mutable.Map[Symbol, immutable.Set[Symbol]]() withDefaultValue immutable.Set[Symbol]() /** Type parameters that survive when specializing in the specified environment. */ def survivingParams(params: List[Symbol], env: TypeEnv) = - params.filter(p => !isSpecialized(p) || !isPrimitive(env(p))) + params.filter(p => !isSpecialized(p) || !isScalaValueType(env(p))) /** Produces the symbols from type parameters `syms` of the original owner, * in the given type environment `env`. The new owner is `nowner`. @@ -535,7 +486,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (p.typeSymbol.isTrait) res += stp else if (currentRun.compiles(clazz)) reporter.warning(clazz.pos, p.typeSymbol + " must be a trait. Specialized version of " - + clazz + " will inherit generic " + p) // TODO change to error + + clazz + " will inherit generic " + p) // TODO change to error } res.reverse.toList } @@ -550,9 +501,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (newClassTParams.isEmpty) infoType else PolyType(newClassTParams, infoType) } - // log("specializedClass " + cls + ": " + specializedInfoType) atPhase(phase.next)(cls.setInfo(specializedInfoType)) - val fullEnv = outerEnv ++ env /** Enter 'sym' in the scope of the current specialized class. It's type is @@ -587,56 +536,57 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * def m$I(x: Int) = <body>/adapted to env {A -> Int} // om */ def forwardToOverload(m: Symbol): Symbol = { - // log("forw. to overload " + m) - val specMember = enterMember(m.cloneSymbol(cls)).setFlag(OVERRIDE | SPECIALIZED).resetFlag(DEFERRED | CASEACCESSOR) // m1 - val om = specializedOverload(cls, m, env).setFlag(OVERRIDE) - // log("created specialized overload" + om) + val specMember = ( + enterMember(m cloneSymbol cls) + setFlag (OVERRIDE | SPECIALIZED) + resetFlag (DEFERRED | CASEACCESSOR) + ) // m1 - var original = info.get(m) match { + val om = specializedOverload(cls, m, env).setFlag(OVERRIDE) + val original = info.get(m) match { case Some(NormalizedMember(tg)) => tg - case _ => m + case _ => m } + info(specMember) = Forward(om) + info(om) = if (original.isDeferred) Forward(original) else Implementation(original) + typeEnv(om) = env ++ typeEnv(m) // add the environment for any method tparams - info(specMember) = Forward(om) - info(om) = if (original.isDeferred) Forward(original) else Implementation(original) - typeEnv(om) = env ++ typeEnv(m) // add the environment for any method tparams - overloads(specMember) = Overload(om, typeEnv(om)) :: overloads(specMember) - + overloads(specMember) ::= Overload(om, typeEnv(om)) enterMember(om) } - log("specializedClass: " + cls) - for (m <- normMembers if needsSpecialization(outerEnv ++ env, m) && satisfiable(fullEnv)) { - // log(" * looking at: " + m + "; wasspecfor: " + wasSpecializedForTypeVars(m)) - if (!m.isDeferred) addConcreteSpecMethod(m) - + for (m <- normMembers ; if needsSpecialization(outerEnv ++ env, m) && satisfiable(fullEnv)) { + if (!m.isDeferred) + addConcreteSpecMethod(m) // specialized members have to be overridable. - if (m.hasFlag(PRIVATE)) + if (m.isPrivate) m.resetFlag(PRIVATE).setFlag(PROTECTED) if (m.isConstructor) { - val specCtor = enterMember(m.cloneSymbol(cls).setFlag(SPECIALIZED)) + val specCtor = enterMember(m.cloneSymbol(cls) setFlag SPECIALIZED) info(specCtor) = Forward(m) - - } else if (isNormalizedMember(m)) { // methods added by normalization + } + else if (isNormalizedMember(m)) { // methods added by normalization val NormalizedMember(original) = info(m) - if (!conflicting(env ++ typeEnv(m))) { + if (nonConflicting(env ++ typeEnv(m))) { if (info(m).degenerate) { - if (settings.debug.value) log("degenerate normalized member " + m + " info(m): " + info(m)) + debuglog("degenerate normalized member " + m + " info(m): " + info(m)) val specMember = enterMember(m.cloneSymbol(cls)).setFlag(SPECIALIZED).resetFlag(DEFERRED) - info(specMember) = Implementation(original) + + info(specMember) = Implementation(original) typeEnv(specMember) = env ++ typeEnv(m) - } else { - // log("om") - val om = forwardToOverload(m) - if (settings.debug.value) log("normalizedMember " + m + " om: " + om + " typeEnv(om): " + typeEnv(om)) } - } else + else debuglog({ + val om = forwardToOverload(m) + "normalizedMember " + m + " om: " + om + " typeEnv(om): " + typeEnv(om) + }) + } + else log("conflicting env for " + m + " env: " + env) - - } else if (m.isDeferred) { // abstract methods + } + else if (m.isDeferred) { // abstract methods val specMember = enterMember(m.cloneSymbol(cls)).setFlag(SPECIALIZED).resetFlag(DEFERRED) - if (settings.debug.value) log("deferred " + specMember.fullName + " is forwarded") + debuglog("deferred " + specMember.fullName + " is forwarded") info(specMember) = new Forward(specMember) { override def target = m.owner.info.member(specializedName(m, env)) @@ -648,20 +598,23 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else if (m.isValue && !m.isMethod) { // concrete value definition def mkAccessor(field: Symbol, name: Name) = { - val sym = cls.newMethod(field.pos, name) - .setFlag(SPECIALIZED | m.getter(clazz).flags) - .resetFlag(LOCAL | PARAMACCESSOR | CASEACCESSOR | LAZY) // we rely on the super class to initialize param accessors + val sym = ( + cls.newMethod(field.pos, name) + setFlag (SPECIALIZED | m.getter(clazz).flags) + resetFlag (LOCAL | PARAMACCESSOR | CASEACCESSOR | LAZY) + // we rely on the super class to initialize param accessors + ) info(sym) = SpecializedAccessor(field) sym } - def overrideIn(clazz: Symbol, sym: Symbol) = { - val sym1 = sym.cloneSymbol(clazz) - .setFlag(OVERRIDE | SPECIALIZED) - .resetFlag(DEFERRED | CASEACCESSOR | PARAMACCESSOR | LAZY) - sym1.setInfo(sym1.info.asSeenFrom(clazz.tpe, sym1.owner)) + val sym1 = ( + sym cloneSymbol clazz + setFlag (OVERRIDE | SPECIALIZED) + resetFlag (DEFERRED | CASEACCESSOR | PARAMACCESSOR | LAZY) + ) + sym1 setInfo sym1.info.asSeenFrom(clazz.tpe, sym1.owner) } - val specVal = specializedOverload(cls, m, env) addConcreteSpecMethod(m) @@ -669,21 +622,20 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { enterMember(specVal) // create accessors - if (settings.debug.value) - log("m: " + m + " isLocal: " + nme.isLocalName(m.name) + " specVal: " + specVal.name + " isLocal: " + nme.isLocalName(specVal.name)) + debuglog("m: " + m + " isLocal: " + nme.isLocalName(m.name) + " specVal: " + specVal.name + " isLocal: " + nme.isLocalName(specVal.name)) if (nme.isLocalName(m.name)) { val specGetter = mkAccessor(specVal, nme.localToGetter(specVal.name)).setInfo(MethodType(List(), specVal.info)) val origGetter = overrideIn(cls, m.getter(clazz)) info(origGetter) = Forward(specGetter) enterMember(specGetter) enterMember(origGetter) - if (settings.debug.value) log("created accessors: " + specGetter + " orig: " + origGetter) + debuglog("created accessors: " + specGetter + " orig: " + origGetter) clazz.caseFieldAccessors.find(_.name.startsWith(m.name)) foreach { cfa => val cfaGetter = overrideIn(cls, cfa) info(cfaGetter) = SpecializedAccessor(specVal) enterMember(cfaGetter) - if (settings.debug.value) log("found case field accessor for " + m + " added override " + cfaGetter); + debuglog("found case field accessor for " + m + " added override " + cfaGetter); } if (specVal.isVariable && m.setter(clazz) != NoSymbol) { @@ -712,49 +664,40 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { cls } - log("specializeClass " + clazz.fullName) - val decls1 = (clazz.info.decls.toList flatMap { m: Symbol => + val decls1 = clazz.info.decls.toList flatMap { m: Symbol => if (m.isAnonymousClass) List(m) else { normalizeMember(m.owner, m, outerEnv) flatMap { normalizedMember => val ms = specializeMember(m.owner, normalizedMember, outerEnv, clazz.info.typeParams) - // log(">>> specialized: " + normalizedMember + " into " + ms) -// atPhase(currentRun.typerPhase)(println("normalizedMember.info: " + normalizedMember.info)) - bring the info to the typer phase // interface traits have concrete members now if (ms.nonEmpty && clazz.isTrait && clazz.isInterface) clazz.resetFlag(INTERFACE) if (normalizedMember.isMethod) { val newTpe = subst(outerEnv, normalizedMember.info) - if (newTpe != normalizedMember.info) // only do it when necessary, otherwise the method type might be at a later phase already - normalizedMember.updateInfo(newTpe) :: ms - else - normalizedMember :: ms - } else - normalizedMember :: ms + // only do it when necessary, otherwise the method type might be at a later phase already + if (newTpe != normalizedMember.info) { + normalizedMember updateInfo newTpe + } + } + normalizedMember :: ms } } - }) - //log("decls before: " + decls1 + ", overloads: " + overloads.mkString("\n")) - - var hasSubclasses = false - // log("For " + clazz + " - " + specializations(clazz.info.typeParams)) - for (env <- specializations(clazz.info.typeParams) if satisfiable(env)) { - val spc = specializedClass(env, decls1) - // log("entered " + spc + " in " + clazz.owner) - hasSubclasses = true + } + + val subclasses = specializations(clazz.info.typeParams) filter satisfiable + subclasses foreach { env => + val spc = specializedClass(env, decls1) val existing = clazz.owner.info.decl(spc.name) + // a symbol for the specialized class already exists if there's a classfile for it. // keeping both crashes the compiler on test/files/pos/spec-Function1.scala - if (existing != NoSymbol) { - // log("removing existing symbol for "+ existing) + if (existing != NoSymbol) clazz.owner.info.decls.unlink(existing) - } - atPhase(phase.next)(clazz.owner.info.decls enter spc) //!! assumes fully specialized classes + atPhase(phase.next)(clazz.owner.info.decls enter spc) //!!! assumes fully specialized classes } - if (hasSubclasses) clazz.resetFlag(FINAL) + if (subclasses.nonEmpty) clazz.resetFlag(FINAL) cleanAnyRefSpecCache(clazz, decls1) - //log("decls: " + decls1 + ", overloads: " + overloads.mkString("\n")) decls1 } @@ -768,42 +711,50 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * // etc. */ private def normalizeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv): List[Symbol] = { - if (settings.debug.value) log("normalizeMember: " + sym.fullName) - if (sym.isMethod && !atPhase(currentRun.typerPhase)(sym.typeParams.isEmpty)) { - var (specializingOn, _) = splitParams(sym.info.typeParams) - val unusedStvars = specializingOn filterNot (specializedTypeVars(sym.info).toList contains) - if (unusedStvars.nonEmpty && currentRun.compiles(sym) && !sym.isSynthetic) { - reporter.warning(sym.pos, "%s %s unused or used in non-specializable positions." - .format(unusedStvars.mkString("", ", ", ""), if (unusedStvars.length == 1) "is" else "are")) - unusedStvars foreach (_.removeAnnotation(SpecializedClass)) - specializingOn = specializingOn filterNot (unusedStvars contains) - // tps = sym.info.typeParams filterNot (_.hasAnnotation(SpecializedClass)) + debuglog("normalizeMember: " + sym.fullName) + sym :: ( + if (!sym.isMethod || atPhase(currentRun.typerPhase)(sym.typeParams.isEmpty)) Nil + else { + var specializingOn = specializedParams(sym) + val unusedStvars = specializingOn filterNot specializedTypeVars(sym.info) + + if (unusedStvars.nonEmpty && currentRun.compiles(sym) && !sym.isSynthetic) { + reporter.warning(sym.pos, + "%s %s unused or used in non-specializable positions.".format( + unusedStvars.mkString("", ", ", ""), + if (unusedStvars.length == 1) "is" else "are") + ) + unusedStvars foreach (_ removeAnnotation SpecializedClass) + specializingOn = specializingOn filterNot (unusedStvars contains) + } + for (env0 <- specializations(specializingOn) if needsSpecialization(env0, sym)) yield { + val tps = survivingParams(sym.info.typeParams, env0) + val specMember = sym.cloneSymbol(owner).setFlag(SPECIALIZED).resetFlag(DEFERRED) + val env = mapAnyRefsInSpecSym(env0, sym, specMember) + val (keys, vals) = env.toList.unzip + + specMember.name = specializedName(sym, env) + log("normalizing: " + sym + " to " + specMember + " with params " + tps) + + typeEnv(specMember) = outerEnv ++ env + val tps1 = produceTypeParameters(tps, specMember, env) + tps1 foreach (tp => tp.setInfo(tp.info.subst(keys, vals))) + + // the cloneInfo is necessary so that method parameter symbols are cloned at the new owner + val methodType = sym.info.resultType.subst(keys ++ tps, vals ++ tps1.map(_.tpe)).cloneInfo(specMember) + specMember setInfo polyType(tps1, methodType) + + debuglog("expanded member: " + sym + ": " + sym.info + + " -> " + specMember + + ": " + specMember.info + + " env: " + env + ) + info(specMember) = NormalizedMember(sym) + overloads(sym) ::= Overload(specMember, env) + specMember + } } - val res = sym :: (for (env0 <- specializations(specializingOn) if needsSpecialization(env0, sym)) yield { - val tps = survivingParams(sym.info.typeParams, env0) - val specMember = sym.cloneSymbol(owner).setFlag(SPECIALIZED).resetFlag(DEFERRED) - val env = mapAnyRefsInSpecSym(env0, sym, specMember) - val keys = env.keysIterator.toList; - val vals = env.valuesIterator.toList - specMember.name = specializedName(sym, env) - log("normalizing: " + sym + " to " + specMember + " with params " + tps) - - typeEnv(specMember) = outerEnv ++ env - val tps1 = produceTypeParameters(tps, specMember, env) // cloneSymbols(tps) - for (tp <- tps1) tp.setInfo(tp.info.subst(keys, vals)) - // the cloneInfo is necessary so that method parameter symbols are cloned at the new owner - val methodType = sym.info.resultType.subst(keys ::: tps, vals ::: (tps1 map (_.tpe))).cloneInfo(specMember) - - specMember.setInfo(polyType(tps1, methodType)) - - if (settings.debug.value) log("expanded member: " + sym + ": " + sym.info + " -> " + specMember + ": " + specMember.info + " env: " + env) - info(specMember) = NormalizedMember(sym) - overloads(sym) = Overload(specMember, env) :: overloads(sym) - specMember - }) - //stps foreach (_.removeAttribute(SpecializedClass)) - res - } else List(sym) + ) } /** Specialize member `m` w.r.t. to the outer environment and the type @@ -817,40 +768,46 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def specializeOn(tparams: List[Symbol]): List[Symbol] = for (spec0 <- specializations(tparams)) yield { val spec = mapAnyRefsInOrigCls(spec0, owner) - // log("outer env: " + outerEnv) - // log(spec) - if (sym.hasFlag(PRIVATE)) sym.resetFlag(PRIVATE).setFlag(PROTECTED) + if (sym.isPrivate) + sym.resetFlag(PRIVATE).setFlag(PROTECTED) + sym.resetFlag(FINAL) val specMember = subst(outerEnv)(specializedOverload(owner, sym, spec)) typeEnv(specMember) = typeEnv(sym) ++ outerEnv ++ spec wasSpecializedForTypeVars(specMember) ++= spec collect { case (s, tp) if s.tpe == tp => s } + log("sym " + specMember + " was specialized for type vars " + wasSpecializedForTypeVars(specMember)) - if (settings.debug.value) log("added specialized overload: %s in env: %s".format(specMember, typeEnv(specMember))) - overloads(sym) = Overload(specMember, spec) :: overloads(sym) - // log("member spec: " + sym + " with owner " + sym.owner + " in env " + spec + " is " + specMember + " with tp " + specMember.tpe) + debuglog("added specialized overload: %s in env: %s".format(specMember, typeEnv(specMember))) + + overloads(sym) ::= Overload(specMember, spec) specMember } if (sym.isMethod) { - if (settings.debug.value) log("specializeMember %s with tps: %s stvars(sym): %s".format(sym, tps, specializedTypeVars(sym))) - val tps1 = if (sym.isConstructor) tps filter (tp => sym.info.paramTypes.contains(tp)) else tps + debuglog("specializeMember %s with tps: %s stvars(sym): %s".format(sym, tps, specializedTypeVars(sym))) + + val tps1 = if (sym.isConstructor) tps filter (sym.info.paramTypes contains _) else tps val tps2 = tps1 intersect specializedTypeVars(sym).toList - if (!sym.isDeferred) addConcreteSpecMethod(sym) + if (!sym.isDeferred) + addConcreteSpecMethod(sym) - val lst = specializeOn(tps2) map {m => info(m) = SpecialOverload(sym, typeEnv(m)); m} - lst - } else - List() + val ms = specializeOn(tps2) + ms foreach (m => info(m) = SpecialOverload(sym, typeEnv(m))) + ms + } + else Nil } /** Return the specialized overload of `m`, in the given environment. */ private def specializedOverload(owner: Symbol, sym: Symbol, env: TypeEnv): Symbol = { - val specMember = sym.cloneSymbol(owner) // this method properly duplicates the symbol's info + val specMember = sym.cloneSymbol(owner) // this method properly duplicates the symbol's info specMember.name = specializedName(sym, env) - specMember.setInfo(subst(env, specMember.info.asSeenFrom(owner.thisType, sym.owner))) - .setFlag(SPECIALIZED) - .resetFlag(DEFERRED | CASEACCESSOR | ACCESSOR | LAZY) + (specMember + setInfo subst(env, specMember.info.asSeenFrom(owner.thisType, sym.owner)) + setFlag (SPECIALIZED) + resetFlag (DEFERRED | CASEACCESSOR | ACCESSOR | LAZY) + ) } /** For each method m that overrides inherited method m', add a special @@ -864,8 +821,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * this method will return List('apply$spec$II') */ private def specialOverrides(clazz: Symbol): List[Symbol] = { - // log("--> specialOverrides(" + clazz + ")") - /** Return the overridden symbol in syms that needs a specialized overriding symbol, * together with its specialization environment. The overridden symbol may not be * the closest to 'overriding', in a given hierarchy. @@ -874,81 +829,80 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * * m overrides a method whose type contains specialized type variables * * there is a valid specialization environment that maps the overridden method type to m's type. */ - def needsSpecialOverride(overriding: Symbol, syms: List[Symbol]): (Symbol, TypeEnv) = { - def missingSpecializations(baseTvar: Symbol, derivedTvar: Symbol): immutable.Set[Type] = { - val baseSet = concreteTypes(baseTvar).toSet - val derivedSet = concreteTypes(derivedTvar).toSet - baseSet diff derivedSet - } - + def needsSpecialOverride(overriding: Symbol): (Symbol, TypeEnv) = { def checkOverriddenTParams(overridden: Symbol) { - if (currentRun.compiles(overriding)) - for ((baseTvar, derivedTvar) <- overridden.info.typeParams.zip(overriding.info.typeParams); - val missing = missingSpecializations(baseTvar, derivedTvar) - if missing.nonEmpty) - reporter.error(derivedTvar.pos, - "Type parameter has to be specialized at least for the same types as in the overridden method. Missing " + - "types: " + missing.mkString("", ", ", "")) + for ((baseTvar, derivedTvar) <- overridden.info.typeParams.zip(overriding.info.typeParams)) { + val missing = concreteTypes(baseTvar).toSet -- concreteTypes(derivedTvar).toSet + if (missing.nonEmpty) { + reporter.error(derivedTvar.pos, + "Type parameter has to be specialized at least for the same types as in the overridden method. Missing " + + "types: " + missing.mkString("", ", ", "") + ) + } + } } - - // log("checking: " + overriding + " - isParamAccessor: " + overriding.isParamAccessor) - if (!overriding.isParamAccessor) for (overridden <- syms) { - if (settings.debug.value) - log("Overridden: " + overridden.fullName + ": " + overridden.info - + "\n by " + overriding.fullName + ": " + overriding.info) - val stvars = specializedTypeVars(overridden.info) - if (!stvars.isEmpty) { - if (settings.debug.value) log("\t\tspecializedTVars: " + stvars) - checkOverriddenTParams(overridden) - - val env = unify(overridden.info, overriding.info, emptyEnv, false) - if (settings.debug.value) - log("\t\tenv: " + env + "isValid: " + TypeEnv.isValid(env, overridden) - + "found: " + atPhase(phase.next)(overridden.owner.info.decl(specializedName(overridden, env)))) - if (!TypeEnv.restrict(env, stvars).isEmpty - && TypeEnv.isValid(env, overridden) - && atPhase(phase.next)(overridden.owner.info.decl(specializedName(overridden, env))) != NoSymbol) - return (overridden, env) + if (!overriding.isParamAccessor) { + for (overridden <- overriding.allOverriddenSymbols) { + debuglog( + "Overridden: " + overridden.fullName + + ": " + overridden.info + + "\n by " + overriding.fullName + + ": " + overriding.info + ) + val stvars = specializedTypeVars(overridden.info) + if (stvars.nonEmpty) { + debuglog("\t\tspecializedTVars: " + stvars) + if (currentRun compiles overriding) + checkOverriddenTParams(overridden) + + val env = unify(overridden.info, overriding.info, emptyEnv, false) + def atNext = atPhase(phase.next)(overridden.owner.info.decl(specializedName(overridden, env))) + + debuglog("\t\tenv: " + env + "isValid: " + TypeEnv.isValid(env, overridden) + "found: " + atNext) + if (TypeEnv.restrict(env, stvars).nonEmpty && TypeEnv.isValid(env, overridden) && atNext != NoSymbol) + return (overridden, env) + } } } (NoSymbol, emptyEnv) } - - val oms = new mutable.ListBuffer[Symbol] - for (overriding <- clazz.info.decls; - val (overridden, env) = needsSpecialOverride(overriding, overriding.allOverriddenSymbols) - if overridden != NoSymbol) { - val om = specializedOverload(clazz, overridden, env) - log("Added specialized overload %s for %s in env: %s with type: %s".format(om, overriding.fullName, env, om.info)) - typeEnv(om) = env - addConcreteSpecMethod(overriding) - if (!overriding.isDeferred) { // concrete method - // if the override is a normalized member, 'om' gets the implementation from - // its original target, and adds the environment of the normalized member (that is, - // any specialized /method/ type parameter bindings) - info(om) = info.get(overriding) match { - case Some(NormalizedMember(target)) => - typeEnv(om) = env ++ typeEnv(overriding) - log(info.get(overriding)) - SpecialOverride(target) - case _ => - log(overriding + ", " + overriding.info) - SpecialOverride(overriding) - } - info(overriding) = Forward(om) - om setPos overriding.pos - } else { // abstract override - if (settings.debug.value) log("abstract override " + overriding.fullName + " with specialized " + om.fullName) - info(om) = Forward(overriding) + (clazz.info.decls flatMap { overriding => + needsSpecialOverride(overriding) match { + case (NoSymbol, _) => None + case (overridden, env) => + val om = specializedOverload(clazz, overridden, env) + log("Added specialized overload %s for %s in env: %s with type: %s".format(om, overriding.fullName, env, om.info)) + typeEnv(om) = env + addConcreteSpecMethod(overriding) + info(om) = ( + if (overriding.isDeferred) { // abstract override + debuglog("abstract override " + overriding.fullName + " with specialized " + om.fullName) + Forward(overriding) + } + else { + // if the override is a normalized member, 'om' gets the + // implementation from its original target, and adds the + // environment of the normalized member (that is, any + // specialized /method/ type parameter bindings) + val impl = info get overriding match { + case Some(NormalizedMember(target)) => + typeEnv(om) = env ++ typeEnv(overriding) + target + case _ => + overriding + } + info(overriding) = Forward(om setPos overriding.pos) + SpecialOverride(impl) + } + ) + overloads(overriding) ::= Overload(om, env) + ifDebug(atPhase(phase.next)(assert( + overridden.owner.info.decl(om.name) != NoSymbol, + "Could not find " + om.name + " in " + overridden.owner.info.decls)) + ) + Some(om) } - overloads(overriding) = Overload(om, env) :: overloads(overriding) - oms += om - atPhase(phase.next)( - assert(overridden.owner.info.decl(om.name) != NoSymbol, - "Could not find " + om.name + " in " + overridden.owner.info.decls)) - } - log("special overrides(%s) = %s".format(clazz, oms)) - oms.toList + }).toList } case object UnifyError extends scala.util.control.ControlThrowable @@ -959,15 +913,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * * If `strict` is true, a UnifyError is thrown if unification is impossible. */ - private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = { -// println("\tunify \t" + tp1 + "\n\t\t" + tp2) - //log("Unify - " + (tp1.getClass, tp2.getClass)) - (tp1, tp2) match { + private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = (tp1, tp2) match { case (TypeRef(_, sym1, _), _) if isSpecialized(sym1) => log("Unify - basic case: " + tp1 + ", " + tp2) - if (definitions.isValueClass(tp2.typeSymbol)) - env + ((sym1, tp2)) - else if (isSpecializedOnAnyRef(sym1) && subtypeOfAnyRef(tp2)) // u.t.b. tp2 <:< AnyRefClass.tpe + if (isValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1)) env + ((sym1, tp2)) else if (strict) throw UnifyError else env @@ -990,17 +939,16 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case (PolyType(_, res), other) => unify(res, other, env, strict) case (ThisType(_), ThisType(_)) => env - case (_, SingleType(_, _)) => unify(tp1, tp2.underlying, env, strict) - case (SingleType(_, _), _) => unify(tp1.underlying, tp2, env, strict) - case (ThisType(_), _) => unify(tp1.widen, tp2, env, strict) - case (_, ThisType(_)) => unify(tp1, tp2.widen, env, strict) + case (_, SingleType(_, _)) => unify(tp1, tp2.underlying, env, strict) + case (SingleType(_, _), _) => unify(tp1.underlying, tp2, env, strict) + case (ThisType(_), _) => unify(tp1.widen, tp2, env, strict) + case (_, ThisType(_)) => unify(tp1, tp2.widen, env, strict) case (RefinedType(_, _), RefinedType(_, _)) => env - case (AnnotatedType(_, tp1, _), tp2) => unify(tp2, tp1, env, strict) - case (ExistentialType(_, res1), _) => unify(tp2, res1, env, strict) + case (AnnotatedType(_, tp1, _), tp2) => unify(tp2, tp1, env, strict) + case (ExistentialType(_, res1), _) => unify(tp2, res1, env, strict) case _ => log("don't know how to unify %s [%s] with %s [%s]".format(tp1, tp1.getClass, tp2, tp2.getClass)) env - } } private def unify(tp1: List[Type], tp2: List[Type], env: TypeEnv, strict: Boolean): TypeEnv = @@ -1008,7 +956,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (!strict) unify(args._1, args._2, env, strict) else { val nenv = unify(args._1, args._2, emptyEnv, strict) - if (env.keySet.intersect(nenv.keySet) == Set()) env ++ nenv + if (env.keySet intersect nenv.keySet isEmpty) env ++ nenv else { log("could not unify: u(" + args._1 + ", " + args._2 + ") yields " + nenv + ", env: " + env) throw UnifyError @@ -1016,8 +964,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } - private def specializedTypes(tps: List[Symbol]) = tps.filter(_.hasAnnotation(SpecializedClass)) - /** Map class symbols to the type environments where they were created. */ val typeEnv: mutable.Map[Symbol, TypeEnv] = new mutable.HashMap[Symbol, TypeEnv] { override def default(key: Symbol) = emptyEnv @@ -1034,44 +980,38 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ private def subst(env: TypeEnv, tpe: Type): Type = { class FullTypeMap(from: List[Symbol], to: List[Type]) extends SubstTypeMap(from, to) { - override def mapOver(tp: Type): Type = tp match { case ClassInfoType(parents, decls, clazz) => - val parents1 = parents mapConserve (this); + val parents1 = parents mapConserve this val declsList = decls.toList - val decls1 = mapOver(declsList); + val decls1 = mapOver(declsList) + if ((parents1 eq parents) && (decls1 eq declsList)) tp else ClassInfoType(parents1, new Scope(decls1), clazz) + case AnnotatedType(annots, atp, selfsym) => val annots1 = mapOverAnnotations(annots) - val atp1 = this(atp) + val atp1 = this(atp) + if ((annots1 eq annots) && (atp1 eq atp)) tp else if (annots1.isEmpty) atp1 - else if (atp1 ne atp) { - val annots2 = annots1.filter(_.atp.typeSymbol != definitions.uncheckedVarianceClass) - if (annots2.isEmpty) atp1 - else AnnotatedType(annots2, atp1, selfsym) - } else - AnnotatedType(annots1, atp1, selfsym) - + else if (atp1 eq atp) AnnotatedType(annots1, atp1, selfsym) + else annots1.filter(_.atp.typeSymbol != uncheckedVarianceClass) match { + case Nil => atp1 + case annots2 => AnnotatedType(annots2, atp1, selfsym) + } case _ => super.mapOver(tp) } } - // disabled because of bugs in std. collections - //val (keys, values) = env.iterator.toList.unzip - val keys = env.keysIterator.toList - val values = env.valuesIterator.toList + val (keys, values) = env.toList.unzip (new FullTypeMap(keys, values))(tpe) -// tpe.subst(keys, values) } private def subst(env: TypeEnv)(decl: Symbol): Symbol = { - val tpe = subst(env, decl.info) - decl.setInfo(if (decl.isConstructor) tpe match { - case MethodType(args, resTpe) => MethodType(args, decl.owner.tpe) - } else tpe) - // log((decl, decl.tpe.bounds.hi)) - // decl + decl setInfo (subst(env, decl.info) match { + case MethodType(args, _) if decl.isConstructor => MethodType(args, decl.owner.tpe) + case tpe => tpe + }) } /** Checks if the type parameter symbol is not specialized @@ -1101,40 +1041,33 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * If it is a 'no-specialization' run, it is applied only to loaded symbols. */ override def transformInfo(sym: Symbol, tpe: Type): Type = { - val res = if (!settings.nospecialization.value || !currentRun.compiles(sym)) tpe match { + 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 - // log("!!! %s[%s]) Parents: %s -> %s".format(sym, targs, base, parents)) - // for (t <- targs; p <- parents) notSpecializedIn(t, p) - if (settings.debug.value) log("transformInfo (poly) " + clazz + " with parents1: " + parents + " ph: " + phase) -// if (clazz.name.toString == "$colon$colon") -// (new Throwable).printStackTrace - polyType(targs, ClassInfoType(parents, - new Scope(specializeClass(clazz, typeEnv(clazz)) ::: specialOverrides(clazz)), - clazz)) + 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)) + atPhase(phase.next)(base map (_.typeSymbol.info)) + // side effecting? parents is not used except to log. val parents = base map specializedType - if (settings.debug.value) log("transformInfo " + clazz + " with parents1: " + parents + " ph: " + phase) - val res = ClassInfoType(base map specializedType, - new Scope(specializeClass(clazz, typeEnv(clazz)) ::: specialOverrides(clazz)), - clazz) - res - + debuglog("transformInfo " + clazz + " with parents1: " + parents + " ph: " + phase) + ClassInfoType( + base map specializedType, + new Scope(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz)), + clazz + ) case _ => tpe - } else tpe - res - - } - - def conflicting(env: TypeEnv): Boolean = { - val silent = (pos: Position, str: String) => () - conflicting(env, silent) + } } /** Is any type variable in `env` conflicting with any if its type bounds, when @@ -1142,13 +1075,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * * A conflicting type environment could still be satisfiable. */ - def conflicting(env: TypeEnv, warn: (Position, String) => Unit): Boolean = - env exists { case (tvar, tpe) => - if (!((subst(env, tvar.info.bounds.lo) <:< tpe) - && (tpe <:< subst(env, tvar.info.bounds.hi)))) { - warn(tvar.pos, "Bounds prevent specialization for " + tvar) - true - } else false + def conflicting(env: TypeEnv) = !nonConflicting(env) + def nonConflicting(env: TypeEnv) = env forall { case (tvar, tpe) => + (subst(env, tvar.info.bounds.lo) <:< tpe) && (tpe <:< subst(env, tvar.info.bounds.hi)) } /** The type environment is sound w.r.t. to all type bounds or only soft @@ -1157,31 +1086,32 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * that does not fall within the bounds, but whose bounds contain * type variables that are @specialized, (that could become satisfiable). */ - def satisfiable(env: TypeEnv, warn: (Position, String) => Unit): Boolean = { + def satisfiable(env: TypeEnv): Boolean = satisfiable(env, false) + def satisfiable(env: TypeEnv, warnings: Boolean): Boolean = { def matches(tpe1: Type, tpe2: Type): Boolean = { val t1 = subst(env, tpe1) val t2 = subst(env, tpe2) ((t1 <:< t2) - || !specializedTypeVars(t1).isEmpty - || !specializedTypeVars(t2).isEmpty) + || specializedTypeVars(t1).nonEmpty + || specializedTypeVars(t2).nonEmpty) } env forall { case (tvar, tpe) => - ((matches(tvar.info.bounds.lo, tpe) - && matches(tpe, tvar.info.bounds.hi)) - || { warn(tvar.pos, "Bounds prevent specialization of " + tvar); - log("specvars: " - + tvar.info.bounds.lo + ": " + specializedTypeVars(tvar.info.bounds.lo) - + " " + subst(env, tvar.info.bounds.hi) + ": " + specializedTypeVars(subst(env, tvar.info.bounds.hi))) - false }) + matches(tvar.info.bounds.lo, tpe) && matches(tpe, tvar.info.bounds.hi) || { + if (warnings) + reporter.warning(tvar.pos, "Bounds prevent specialization of " + tvar) + + log("specvars: " + + tvar.info.bounds.lo + ": " + + specializedTypeVars(tvar.info.bounds.lo) + " " + + subst(env, tvar.info.bounds.hi) + ": " + + specializedTypeVars(subst(env, tvar.info.bounds.hi)) + ) + false + } } } - def satisfiable(env: TypeEnv): Boolean = { - val silent = (pos: Position, str: String) => () - satisfiable(env, silent) - } - class Duplicator extends { val global: SpecializeTypes.this.global.type = SpecializeTypes.this.global } with typechecker.Duplicators @@ -1217,12 +1147,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { override def transform(tree: Tree): Tree = tree match { case Select(qual, name) => val sym = tree.symbol - if (sym.hasFlag(PRIVATE)) - if (settings.debug.value) - log("seeing private member %s, currentClass: %s, owner: %s, isAccessible: %b, isLocalName: %b" - .format(sym, currentClass, sym.owner.enclClass, isAccessible(sym), nme.isLocalName(sym.name))) + if (sym.isPrivate) debuglog( + "seeing private member %s, currentClass: %s, owner: %s, isAccessible: %b, isLocalName: %b".format( + sym, currentClass, sym.owner.enclClass, isAccessible(sym), nme.isLocalName(sym.name)) + ) if (shouldMakePublic(sym) && !isAccessible(sym)) { - if (settings.debug.value) log("changing private flag of " + sym) + debuglog("changing private flag of " + sym) sym.makeNotPrivate(sym.owner) } super.transform(tree) @@ -1234,13 +1164,13 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Return the generic class corresponding to this specialized class. */ def originalClass(clazz: Symbol): Symbol = - if (clazz.hasFlag(SPECIALIZED)) { + if (hasSpecializedFlag(clazz)) { val (originalName, _, _) = nme.splitSpecializedName(clazz.name) clazz.owner.info.decl(originalName).suchThat(_.isClass) } else NoSymbol def illegalSpecializedInheritance(clazz: Symbol): Boolean = { - clazz.hasFlag(SPECIALIZED) && originalClass(clazz).info.parents.exists { p => + hasSpecializedFlag(clazz) && originalClass(clazz).info.parents.exists { p => hasSpecializedParams(p.typeSymbol) && !p.typeSymbol.isTrait } } @@ -1258,8 +1188,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { override def traverse(tree: Tree) = tree match { case DefDef(mods, name, tparams, vparamss, tpt, rhs) => if (concreteSpecMethods(tree.symbol) || tree.symbol.isConstructor) { - if (settings.debug.value) - log("!!! adding body of a defdef %s, symbol %s: %s".format(tree, tree.symbol, rhs)) + debuglog("!!! adding body of a defdef %s, symbol %s: %s".format(tree, tree.symbol, rhs)) body(tree.symbol) = rhs // body(tree.symbol) = tree // whole method parameters(tree.symbol) = vparamss map (_ map (_.symbol)) @@ -1333,23 +1262,23 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case TypeApply(Select(qual, name), targs) if (!specializedTypeVars(symbol.info).isEmpty && name != nme.CONSTRUCTOR) => - if (settings.debug.value) log("checking typeapp for rerouting: " + tree + " with sym.tpe: " + symbol.tpe + " tree.tpe: " + tree.tpe) + debuglog("checking typeapp for rerouting: " + tree + " with sym.tpe: " + symbol.tpe + " tree.tpe: " + tree.tpe) val qual1 = transform(qual) // log(">>> TypeApply: " + tree + ", qual1: " + qual1) specSym(qual1) match { case Some(specMember) => - if (settings.debug.value) log("found " + specMember.fullName) - assert(symbol.info.typeParams.length == targs.length) - // log("!!! In TypeApply: " + specMember + "; " + symbol) + debuglog("found " + specMember.fullName) + ifDebug(assert(symbol.info.typeParams.length == targs.length, symbol.info.typeParams + " / " + targs)) + val env = typeEnv(specMember) - // log("env: " + env) - def isResidual(env: TypeEnv, tvar: Symbol) = - !env.isDefinedAt(tvar) || (env.isDefinedAt(tvar) && !isValueClass(env(tvar).typeSymbol)) - val residualTargs = - for ((tvar, targ) <- symbol.info.typeParams.zip(targs) if isResidual(env, tvar)) - yield targ - assert(residualTargs.length == specMember.info.typeParams.length, + val residualTargs = symbol.info.typeParams zip targs collect { + case (tvar, targ) if !env.contains(tvar) || !isValueClass(env(tvar).typeSymbol) => targ + } + + ifDebug(assert(residualTargs.length == specMember.info.typeParams.length, "residual: %s, tparams: %s, env: %s".format(residualTargs, symbol.info.typeParams, env)) + ) + val tree1 = maybeTypeApply(Select(qual1, specMember), residualTargs) log("rewrote " + tree + " to " + tree1) localTyper.typedOperator(atPos(tree.pos)(tree1)) // being polymorphic, it must be a method @@ -1364,15 +1293,15 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { tree case Select(qual, name) => - if (settings.debug.value) - log("[%s] looking at Select: %s sym: %s: %s [tree.tpe: %s]".format(tree.pos.line, tree, symbol, symbol.info, tree.tpe)) + debuglog("[%s] looking at Select: %s sym: %s: %s [tree.tpe: %s]".format( + tree.pos.line, tree, symbol, symbol.info, tree.tpe)) //log("!!! select " + tree + " -> " + symbol.info + " specTypeVars: " + specializedTypeVars(symbol.info)) if (specializedTypeVars(symbol.info).nonEmpty && name != nme.CONSTRUCTOR) { // log("!!! unifying " + (symbol, symbol.tpe) + " and " + (tree, tree.tpe)) val env = unify(symbol.tpe, tree.tpe, emptyEnv, false) // log("!!! found env: " + env + "; overloads: " + overloads(symbol)) - if (settings.debug.value) log("checking for rerouting: " + tree + " with sym.tpe: " + symbol.tpe + " tree.tpe: " + tree.tpe + " env: " + env) + debuglog("checking for rerouting: " + tree + " with sym.tpe: " + symbol.tpe + " tree.tpe: " + tree.tpe + " env: " + env) if (!env.isEmpty) { val specMember = overload(symbol, env) //log("!!! found member: " + specMember) @@ -1397,7 +1326,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else overloads(symbol).find(_.sym.info =:= symbol.info) match { case Some(specMember) => val qual1 = transform(qual) - if (settings.debug.value) log("** routing " + tree + " to " + specMember.sym.fullName + " tree: " + Select(qual1, specMember.sym)) + debuglog("** routing " + tree + " to " + specMember.sym.fullName + " tree: " + Select(qual1, specMember.sym)) localTyper.typedOperator(atPos(tree.pos)(Select(qual1, specMember.sym))) case None => super.transform(tree) @@ -1442,7 +1371,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { assert(body.isDefinedAt(target), "sym: " + symbol.fullName + " target: " + target.fullName) // we have an rhs, specialize it val tree1 = duplicateBody(ddef, target) - if (settings.debug.value) log("implementation: " + tree1) + debuglog("implementation: " + tree1) val DefDef(mods, name, tparams, vparamss, tpt, rhs) = tree1 treeCopy.DefDef(tree1, mods, name, tparams, vparamss, tpt, transform(rhs)) @@ -1456,7 +1385,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else { // we have an rhs, specialize it val tree1 = duplicateBody(ddef, target) - if (settings.debug.value) log("implementation: " + tree1) + debuglog("implementation: " + tree1) val DefDef(mods, name, tparams, vparamss, tpt, rhs) = tree1 treeCopy.DefDef(tree1, mods, name, tparams, vparamss, tpt, transform(rhs)) } @@ -1469,14 +1398,13 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { // we have an rhs, specialize it val tree1 = addBody(ddef, target) (new ChangeOwnerTraverser(target, tree1.symbol))(tree1.rhs) - if (settings.debug.value) - log("changed owners, now: " + tree1) + debuglog("changed owners, now: " + tree1) val DefDef(mods, name, tparams, vparamss, tpt, rhs) = tree1 treeCopy.DefDef(tree1, mods, name, tparams, vparamss, tpt, transform(rhs)) case SpecialOverload(original, env) => - if (settings.debug.value) log("completing specialized " + symbol.fullName + " calling " + original) + debuglog("completing specialized " + symbol.fullName + " calling " + original) log("special overload " + original + " -> " + env) val t = DefDef(symbol, { vparamss => val fun = Apply(Select(This(symbol.owner), original), @@ -1488,14 +1416,13 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { symbol.owner.thisType.memberType(original).finalResultType) }) log("created special overload tree " + t) - if (settings.debug.value) log("created " + t) + debuglog("created " + t) localTyper.typed(t) case fwd @ Forward(_) => log("forward: " + fwd + ", " + ddef) val rhs1 = forwardCall(tree.pos, gen.mkAttributedRef(symbol.owner.thisType, fwd.target), vparamss) - if (settings.debug.value) - log("completed forwarder to specialized overload: " + fwd.target + ": " + rhs1) + debuglog("completed forwarder to specialized overload: " + fwd.target + ": " + rhs1) localTyper.typed(treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, rhs1)) case SpecializedAccessor(target) => @@ -1508,16 +1435,17 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } case ValDef(mods, name, tpt, rhs) if symbol.hasFlag(SPECIALIZED) && !symbol.isParamAccessor => - assert(body.isDefinedAt(symbol.alias)) + assert(body.isDefinedAt(symbol.alias), body) val tree1 = treeCopy.ValDef(tree, mods, name, tpt, body(symbol.alias).duplicate) - if (settings.debug.value) log("now typing: " + tree1 + " in " + tree.symbol.owner.fullName) + debuglog("now typing: " + tree1 + " in " + tree.symbol.owner.fullName) val d = new Duplicator - val tree2 = d.retyped(localTyper.context1.asInstanceOf[d.Context], - tree1, - symbol.alias.enclClass, - symbol.enclClass, - typeEnv(symbol.alias) ++ typeEnv(tree.symbol)) - val ValDef(mods1, name1, tpt1, rhs1) = tree2 + val ValDef(mods1, name1, tpt1, rhs1) = d.retyped( + localTyper.context1.asInstanceOf[d.Context], + tree1, + symbol.alias.enclClass, + symbol.enclClass, + typeEnv(symbol.alias) ++ typeEnv(tree.symbol) + ) val t = treeCopy.ValDef(tree1, mods1, name1, tpt1, transform(rhs1)) log("valdef " + tree + " -> " + t) t @@ -1527,18 +1455,18 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { // localTyper.typed( // Apply(Select(Super(currentClass, nme.EMPTY), symbol.alias.getter(symbol.alias.owner)), // List()))) -// if (settings.debug.value) log("replaced ValDef: " + tree1 + " in " + tree.symbol.owner.fullName) +// debuglog("replaced ValDef: " + tree1 + " in " + tree.symbol.owner.fullName) // tree1 case Apply(sel @ Select(sup @ Super(qual, name), name1), args) if (sup.symbol.info.parents != atPhase(phase.prev)(sup.symbol.info.parents)) => def parents = sup.symbol.info.parents - if (settings.debug.value) log(tree + " parents changed from: " + atPhase(phase.prev)(parents) + " to: " + parents) + debuglog(tree + " parents changed from: " + atPhase(phase.prev)(parents) + " to: " + parents) val res = localTyper.typed( Apply(Select(Super(qual, name) setPos sup.pos, name1) setPos sel.pos, transformTrees(args)) setPos tree.pos) - if (settings.debug.value) log("retyping call to super, from: " + symbol + " to " + res.symbol) + debuglog("retyping call to super, from: " + symbol + " to " + res.symbol) res case _ => @@ -1555,28 +1483,19 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { private def duplicateBody(tree: DefDef, source: Symbol) = { val symbol = tree.symbol - val meth = addBody(tree, source) - if (settings.debug.value) log("now typing: " + meth + " in " + symbol.owner.fullName) + val meth = addBody(tree, source) + debuglog("now typing: " + meth + " in " + symbol.owner.fullName) + val d = new Duplicator - try { - // log("duplicating tree: " + tree + "; " + symbol.owner) - // log("source: " + source + "; owner: " + source.owner) - // log("source encl class: " + source.enclClass) - // log("symbol encl class: " + symbol.enclClass) - // log(meth) - d.retyped(localTyper.context1.asInstanceOf[d.Context], - meth, - source.enclClass, - symbol.enclClass, - typeEnv(source) ++ typeEnv(symbol)) - } catch { - case e => - println("error compiling %s [%s]".format(unit, tree.pos)) - throw e - } + d.retyped( + localTyper.context1.asInstanceOf[d.Context], + meth, + source.enclClass, + symbol.enclClass, + typeEnv(source) ++ typeEnv(symbol) + ) } - /** Put the body of 'source' as the right hand side of the method 'tree'. * The destination method gets fresh symbols for type and value parameters, * and the body is updated to the new symbols, and owners adjusted accordingly. @@ -1585,13 +1504,13 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ private def addBody(tree: DefDef, source: Symbol): DefDef = { val symbol = tree.symbol - if (settings.debug.value) log("specializing body of" + symbol.fullName + ": " + symbol.info) + debuglog("specializing body of" + symbol.fullName + ": " + symbol.info) val DefDef(mods, name, tparams, vparamss, tpt, _) = tree // val (_, origtparams) = splitParams(source.typeParams) val env = typeEnv(symbol) val boundTvars = env.keySet - val origtparams = source.typeParams.filter(tparam => !boundTvars(tparam) || !isPrimitive(env(tparam))) - if (settings.debug.value) log("substituting " + origtparams + " for " + symbol.typeParams) + val origtparams = source.typeParams.filter(tparam => !boundTvars(tparam) || !isScalaValueType(env(tparam))) + debuglog("substituting " + origtparams + " for " + symbol.typeParams) // skolemize type parameters val (oldtparams, newtparams) = reskolemize(tparams) @@ -1617,10 +1536,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { treeCopy.DefDef(tree, mods, name, tparams, vparamss1, tpt, tmp) } - def warn(clazz: Symbol)(pos: Position, err: String) = - if (!clazz.hasFlag(SPECIALIZED)) - unit.warning(pos, err) - /** Create trees for specialized members of 'cls', based on the * symbols that are already there. */ @@ -1634,7 +1549,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { for (m <- cls.info.decls.toList if m.hasFlag(SPECIALIZED) && (m.sourceFile ne null) - && satisfiable(typeEnv(m), warn(cls))) { + && satisfiable(typeEnv(m), !cls.hasFlag(SPECIALIZED))) { log("creating tree for " + m.fullName) if (m.isMethod) { if (info(m).target.hasAccessorFlag) hasSpecializedFields = true @@ -1760,40 +1675,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (currentRun.compiles(m)) concreteSpecMethods += m } - private def makeArguments(fun: Symbol, vparams: List[Symbol]): List[Tree] = { - def needsCast(tp1: Type, tp2: Type): Boolean = - !(tp1 <:< tp2) - + private def makeArguments(fun: Symbol, vparams: List[Symbol]): List[Tree] = ( //! TODO: make sure the param types are seen from the right prefix - for ((tp, arg) <- fun.info.paramTypes zip vparams) yield { - if (needsCast(arg.tpe, tp)) { - //log("tp: " + tp + " " + tp.typeSymbol.owner) - gen.mkAsInstanceOf(Ident(arg), tp) - } else Ident(arg) - } - } - + for ((tp, arg) <- fun.info.paramTypes zip vparams) yield + gen.maybeMkAsInstanceOf(Ident(arg), tp, arg.tpe) + ) private def findSpec(tp: Type): Type = tp match { - case TypeRef(pre, sym, args) => - if (args.isEmpty) tp - else { - specializedType(tp) - /*log("looking for " + specializedName(sym.name, args) + " in " + pre) - val sym1 = pre.member(specializedName(sym.name, args)) - assert(sym1 != NoSymbol, "pre: " + pre.typeSymbol + " ph: " + phase + " with: " + pre.members) - TypeRef(pre, sym1, Nil)*/ - } - case _ => tp + case TypeRef(pre, sym, _ :: _) => specializedType(tp) + case _ => tp } class SpecializationTransformer(unit: CompilationUnit) extends Transformer { informProgress("specializing " + unit) override def transform(tree: Tree) = if (settings.nospecialization.value) tree - else atPhase(phase.next) { - val res = specializeCalls(unit).transform(tree) - res - } + else atPhase(phase.next)(specializeCalls(unit).transform(tree)) } def printSpecStats() { |