From e512518d25818b4b0381e4a078137734f8eab12f Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 19 Feb 2012 15:35:36 -0800 Subject: Streamlining skolemization, specialization. Skolemization code doesn't belong in Typers. I carved out a little place for it. Also simplifications in specialization. --- .../reflect/internal/ExistentialsAndSkolems.scala | 50 ++++++++++++++++++++++ .../scala/reflect/internal/SymbolTable.scala | 1 + src/compiler/scala/reflect/internal/Symbols.scala | 2 + .../tools/nsc/transform/SpecializeTypes.scala | 37 +++++++--------- .../scala/tools/nsc/typechecker/Namers.scala | 9 ++-- .../scala/tools/nsc/typechecker/Typers.scala | 34 --------------- 6 files changed, 75 insertions(+), 58 deletions(-) create mode 100644 src/compiler/scala/reflect/internal/ExistentialsAndSkolems.scala (limited to 'src') diff --git a/src/compiler/scala/reflect/internal/ExistentialsAndSkolems.scala b/src/compiler/scala/reflect/internal/ExistentialsAndSkolems.scala new file mode 100644 index 0000000000..47f794681c --- /dev/null +++ b/src/compiler/scala/reflect/internal/ExistentialsAndSkolems.scala @@ -0,0 +1,50 @@ +/* NSC -- new scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package internal + +import scala.collection.{ mutable, immutable } +import util._ + +/** The name of this trait defines the eventual intent better than + * it does the initial contents. + */ +trait ExistentialsAndSkolems { + self: SymbolTable => + + /** Map a list of type parameter symbols to skolemized symbols, which + * can be deskolemized to the original type parameter. (A skolem is a + * representation of a bound variable when viewed inside its scope.) + * !!!Adriaan: this does not work for hk types. + */ + def deriveFreshSkolems(tparams: List[Symbol]): List[Symbol] = { + class Deskolemizer extends LazyType { + override val typeParams = tparams + val typeSkolems = typeParams map (_.newTypeSkolem setInfo this) + override def complete(sym: Symbol) { + // The info of a skolem is the skolemized info of the + // actual type parameter of the skolem + sym setInfo sym.deSkolemize.info.substSym(typeParams, typeSkolems) + } + } + (new Deskolemizer).typeSkolems + } + + /** Convert to corresponding type parameters all skolems of method + * parameters which appear in `tparams`. + */ + def deskolemizeTypeParams(tparams: List[Symbol])(tp: Type): Type = { + class DeSkolemizeMap extends TypeMap { + def apply(tp: Type): Type = tp match { + case TypeRef(pre, sym, args) if sym.isTypeSkolem && (tparams contains sym.deSkolemize) => + mapOver(typeRef(NoPrefix, sym.deSkolemize, args)) + case _ => + mapOver(tp) + } + } + new DeSkolemizeMap mapOver tp + } +} diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 1973a97279..b3c62bffbf 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -15,6 +15,7 @@ abstract class SymbolTable extends api.Universe with Symbols with Types with Kinds + with ExistentialsAndSkolems with Scopes with Definitions with Constants diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 8e9788e8b6..ce85d65050 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -2714,6 +2714,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def cloneSymbolsAndModify(syms: List[Symbol], infoFn: Type => Type): List[Symbol] = cloneSymbols(syms) map (_ modifyInfo infoFn) + def cloneSymbolsAtOwnerAndModify(syms: List[Symbol], owner: Symbol, infoFn: Type => Type): List[Symbol] = + cloneSymbolsAtOwner(syms, owner) map (_ modifyInfo infoFn) /** Functions which perform the standard clone/substituting on the given symbols and type, * then call the creator function with the new symbols and type as arguments. diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index fddb379a07..8f02194486 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -1226,18 +1226,18 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val body: mutable.Map[Symbol, Tree] = new mutable.HashMap /** Map a specializable method to its value parameter symbols. */ - val parameters: mutable.Map[Symbol, List[List[Symbol]]] = new mutable.HashMap + val parameters = mutable.HashMap[Symbol, List[Symbol]]() /** Collect method bodies that are concrete specialized methods. */ class CollectMethodBodies extends Traverser { override def traverse(tree: Tree) = tree match { - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + case DefDef(mods, name, tparams, vparams :: Nil, tpt, rhs) => if (concreteSpecMethods(tree.symbol) || tree.symbol.isConstructor) { 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) = mmap(vparamss)(_.symbol) + parameters(tree.symbol) = vparams.map(_.symbol) concreteSpecMethods -= tree.symbol } // no need to descend further down inside method bodies @@ -1531,12 +1531,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } - private def reskolemize(tparams: List[TypeDef]): (List[Symbol], List[Symbol]) = { - val saved = tparams map (_.symbol) - localTyper skolemizeTypeParams tparams - (saved, tparams map (_.symbol)) - } - private def duplicateBody(tree: DefDef, source: Symbol) = { val symbol = tree.symbol val meth = addBody(tree, source) @@ -1560,8 +1554,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ private def addBody(tree: DefDef, source: Symbol): DefDef = { val symbol = tree.symbol - debuglog("specializing body of" + symbol.fullName + ": " + symbol.info) - val DefDef(mods, name, tparams, vparamss, tpt, _) = tree + debuglog("specializing body of" + symbol.defString) + val DefDef(mods, name, tparams, vparams :: Nil, tpt, _) = tree // val (_, origtparams) = splitParams(source.typeParams) val env = typeEnv(symbol) val boundTvars = env.keySet @@ -1569,12 +1563,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { debuglog("substituting " + origtparams + " for " + symbol.typeParams) // skolemize type parameters - val (oldtparams, newtparams) = reskolemize(tparams) + val oldtparams = tparams map (_.symbol) + val newtparams = deriveFreshSkolems(oldtparams) + map2(tparams, newtparams)(_ setSymbol _) // create fresh symbols for value parameters to hold the skolem types - val vparamss1 = List(for (vdef <- vparamss.head; param = vdef.symbol) yield { - ValDef(param cloneSymbol symbol substInfo (oldtparams, newtparams)) - }) + val newSyms = cloneSymbolsAtOwnerAndModify(vparams map (_.symbol), symbol, _.substSym(oldtparams, newtparams)) // replace value and type parameters of the old method with the new ones // log("Adding body for " + tree.symbol + " - origtparams: " + origtparams + "; tparams: " + tparams) @@ -1582,14 +1576,15 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { // log("Type env of: " + tree.symbol + ": " + boundTvars) // log("newtparams: " + newtparams) val symSubstituter = new ImplementationAdapter( - parameters(source).flatten ::: origtparams, - vparamss1.flatten.map(_.symbol) ::: newtparams, + parameters(source) ::: origtparams, + newSyms ::: newtparams, source.enclClass, false) // don't make private fields public - val tmp = symSubstituter(body(source).duplicate) + + val newBody = symSubstituter(body(source).duplicate) tpt.tpe = tpt.tpe.substSym(oldtparams, newtparams) - treeCopy.DefDef(tree, mods, name, tparams, vparamss1, tpt, tmp) + treeCopy.DefDef(tree, mods, name, tparams, List(newSyms map ValDef), tpt, newBody) } /** Create trees for specialized members of 'sClass', based on the @@ -1610,9 +1605,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (m.isMethod) { if (info(m).target.hasAccessorFlag) hasSpecializedFields = true if (m.isClassConstructor) { - val origParamss = parameters(info(m).target) + val origParams = parameters(info(m).target) val vparams = ( - map2(m.info.paramTypes, origParamss(0))((tp, sym) => + map2(m.info.paramTypes, origParams)((tp, sym) => m.newValue(specializedName(sym, typeEnv(sClass)), sym.pos, sym.flags) setInfo tp ) ) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 51542ec757..3347d2e767 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1299,7 +1299,7 @@ trait Namers extends MethodSynthesis { catch typeErrorHandler(tree, ErrorType) result match { - case PolyType(tparams @ (tp :: _), _) if tp.owner.isTerm => typer.deskolemizeTypeParams(tparams)(result) + case PolyType(tparams @ (tp :: _), _) if tp.owner.isTerm => deskolemizeTypeParams(tparams)(result) case _ => result } } @@ -1439,8 +1439,11 @@ trait Namers extends MethodSynthesis { private val ownerSym = owner.symbol override val typeParams = tparams map (_.symbol) //@M override val tree = restp.tree - if (ownerSym.isTerm) - typer skolemizeTypeParams tparams + + if (ownerSym.isTerm) { + val skolems = deriveFreshSkolems(tparams map (_.symbol)) + map2(tparams, skolems)(_ setSymbol _) + } def completeImpl(sym: Symbol) = { // @M an abstract type's type parameters are entered. diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 17c0bdf304..1c1f35aac2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3036,40 +3036,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { packSymbols(localSyms.toList, normalizedTpe) } - /** Replace type parameters with their TypeSkolems, which can later - * be deskolemized to the original type param. (A skolem is a - * representation of a bound variable when viewed inside its scope) - * !!!Adriaan: this does not work for hk types. - */ - def skolemizeTypeParams(tparams: List[TypeDef]): List[TypeDef] = { - class Deskolemizer extends LazyType { - override val typeParams = tparams map (_.symbol) - val typeSkolems = typeParams map (_.newTypeSkolem setInfo this) - // Replace the symbols - def substitute() = map2(tparams, typeSkolems)(_ setSymbol _) - override def complete(sym: Symbol) { - // The info of a skolem is the skolemized info of the - // actual type parameter of the skolem - sym setInfo sym.deSkolemize.info.substSym(typeParams, typeSkolems) - } - } - (new Deskolemizer).substitute() - } - /** Convert to corresponding type parameters all skolems of method - * parameters which appear in `tparams`. - */ - def deskolemizeTypeParams(tparams: List[Symbol])(tp: Type): Type = { - class DeSkolemizeMap extends TypeMap { - def apply(tp: Type): Type = tp match { - case TypeRef(pre, sym, args) if sym.isTypeSkolem && (tparams contains sym.deSkolemize) => - mapOver(typeRef(NoPrefix, sym.deSkolemize, args)) - case _ => - mapOver(tp) - } - } - new DeSkolemizeMap mapOver tp - } - def typedClassOf(tree: Tree, tpt: Tree, noGen: Boolean = false) = if (!checkClassType(tpt, true, false) && noGen) tpt else atPos(tree.pos)(gen.mkClassOf(tpt.tpe)) -- cgit v1.2.3