summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
Diffstat (limited to 'sources')
-rw-r--r--sources/scalac/transformer/ExpandMixins.java480
-rw-r--r--sources/scalac/transformer/ExpandMixinsPhase.java163
2 files changed, 330 insertions, 313 deletions
diff --git a/sources/scalac/transformer/ExpandMixins.java b/sources/scalac/transformer/ExpandMixins.java
index 80a46a10a0..dc4d9a04ef 100644
--- a/sources/scalac/transformer/ExpandMixins.java
+++ b/sources/scalac/transformer/ExpandMixins.java
@@ -9,338 +9,224 @@
package scalac.transformer;
-import scalac.*;
-import scalac.util.*;
-import scalac.ast.*;
-import scalac.symtab.*;
-import java.util.*;
-import java.util.Arrays;
-import Tree.*;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import scalac.Global;
+import scalac.ast.Tree;
+import scalac.ast.Tree.Template;
+import scalac.ast.TreeList;
+import scalac.ast.TreeGen;
+import scalac.ast.TreeCloner;
+import scalac.ast.TreeSymbolCloner;
+import scalac.ast.Transformer;
+import scalac.symtab.Modifiers;
+import scalac.symtab.Scope;
+import scalac.symtab.Scope.SymbolIterator;
+import scalac.symtab.Symbol;
+import scalac.symtab.SymbolCloner;
+import scalac.symtab.SymbolSubstTypeMap;
+import scalac.symtab.Type;
+import scalac.util.Name;
+import scalac.util.Debug;
+
+public class ClassExpander {
-/**
- * A transformer to expand mixins using code copying. We assume that
- * links to outer classes have been made explicit by a previous phase.
- *
- * @author Michel Schinz
- * @version 1.0
- */
+ //########################################################################
+ // Private Fields
-// TODO do not copy hidden members which are not accessible via
-// "super".
+ /** The global environment */
+ private final Global global;
-// TODO also substitute type parameters of classes in which the mixin
-// is nested, if any. Do the same for the substitution of symbols in
-// ThisTypes.
+ /** A tree generator */
+ private final TreeGen gen;
-public class ExpandMixins extends Transformer {
- // Mapping from (class) symbols to their definition.
- protected final Map/*<Symbol,Tree>*/ classDefs;
+ /** The expanding class */
+ private final Symbol clasz;
- protected final Definitions defs;
+ /** The parents of the expanding class */
+ private final Type[] parents;
- protected final AddInterfacesPhase addInterfaces;
+ /** The members of the expanding class */
+ private final Scope members;
- public ExpandMixins(Global global, ExpandMixinsPhase descr) {
- super(global);
- defs = global.definitions;
+ /** The template of the expanding class */
+ private final Template template;
- classDefs = descr.classDefs;
+ /** The body of the expanding class */
+ private final TreeList body;
- addInterfaces = global.PHASE.ADDINTERFACES;
- }
+ /** The type map to apply to inlined symbols and trees */
+ private final SymbolSubstTypeMap map;
- public void apply() {
- ClassDefCollector collector = new ClassDefCollector(classDefs);
+ /** The symbol cloner to clone inlined symbols */
+ private final SymbolCloner cloner;
- for (int i = 0; i < global.units.length; i++) {
- Unit unit = global.units[i];
- for (int j = 0; j < unit.body.length; ++j)
- collector.traverse(unit.body[j]);
- }
+ /** The state of this class (used to prevent misuses) */
+ private int state;
- super.apply();
+ //########################################################################
+ // Public Constructors
+
+ public ClassExpander(Global global, Symbol clasz, Template template) {
+ this.global = global;
+ this.gen = global.treeGen;
+ this.clasz = clasz;
+ this.parents = Type.cloneArray(clasz.parents());
+ this.members = clasz.members().cloneScope();
+ this.template = gen.make.Template(template.pos, template.symbol(),
+ Tree.cloneArray(template.parents), template.body);
+ this.template.setType(Type.compoundType(parents, members, clasz));
+ this.body = new TreeList();
+ this.map = new SymbolSubstTypeMap();
+ this.cloner = new SymbolCloner(
+ global.freshNameCreator, new HashMap(), map.getSymbols());
+ this.state = parents.length;
}
- protected void typeSubst(Type type, ArrayList f, ArrayList a) {
- switch (type) {
- case TypeRef(Type pre, Symbol sym, Type[] args): {
- Symbol s = addInterfaces.getClassSymbol(sym);
- f.addAll(Arrays.asList(s.typeParams()));
- a.addAll(Arrays.asList(args));
- typeSubst(pre, f, a);
- } break;
+ //########################################################################
+ // Public Methods
+
+ public void inlineMixin(int i, Type type, Symbol iface, Template impl) {
+ assert 0 < i && i < state : "state = " + state + ", i = " + i;
+ switch (parents[i]) {
+ case TypeRef(Type prefix, Symbol mixin, Type[] args):
+ map.insertSymbol(mixin, clasz);
+ cloner.owners.put(mixin.constructor(), clasz);
+ inlineMixinTParams(type);
+ Tree.Apply constr = (Tree.Apply)template.parents[i];
+ inlineMixinVParams(mixin.valueParams(), constr.args);
+ inlineMixinMembers(impl);
+ parents[i] = Type.TypeRef(prefix, iface, args);
+ template.parents[i] = gen.mkParentConstr(constr.pos, parents[i]);
+ state = i;
+ return;
default:
- ; // nothing to do
+ throw Debug.abort("invalid base class type", parents[i]);
}
}
- protected Object[] typeSubst(Type type) {
- ArrayList/*<Symbol[]>*/ f = new ArrayList();
- ArrayList/*<Type[]>*/ a = new ArrayList();
- typeSubst(type, f, a);
- return new Object[] {
- f.toArray(new Symbol[f.size()]), a.toArray(new Type[a.size()])
+ public Template getTemplate() {
+ assert 0 < state : "state = " + state;
+ Transformer superFixer = new Transformer(global) {
+ public Tree transform(Tree tree) {
+ switch (tree) {
+ case Select(Super(_), _):
+ Symbol symbol = map.lookupSymbol(tree.symbol());
+ if (symbol != null)
+ return gen.Select(gen.This(tree.pos, clasz), symbol);
+ }
+ return super.transform(tree);
+ }
};
+ body.append(superFixer.transform(template.body));
+ template.body = body.toArray();
+ // !!! *1 fix ExpandMixinsPhase.transformInfo and remove next line
+ clasz.updateInfo(template.type());
+ state = 0;
+ return template;
}
- protected void getArgsSection(Tree tree, List s) {
- switch(tree) {
- case Apply(Tree fun, Tree[] args):
- getArgsSection(fun, s);
- s.add(args);
- break;
+ //########################################################################
+ // Private Methods
+ private void inlineMixinTParams(Type type) {
+ switch (type) {
+ case TypeRef(Type prefix, Symbol symbol, Type[] args):
+ map.insertType(symbol.typeParams(), args);
+ if (prefix.symbol() != symbol.owner())
+ inlineMixinTParams(prefix.baseType(symbol.owner()));
+ return;
default:
- ; // nothing to do
+ throw Debug.abort("illegal case", type);
}
}
- protected Tree[][] getArgsSection(Tree tree) {
- List s = new ArrayList();
- getArgsSection(tree, s);
- return (Tree[][])s.toArray(new Tree[s.size()][]);
- }
-
- protected Map/*<Template,Template>*/ expansions = new HashMap();
-
- protected Template getMixinExpandedTemplate(Template tree, Symbol owner) {
- if (! expansions.containsKey(tree))
- expansions.put(tree, expandMixins(tree, owner));
- return (Template)expansions.get(tree);
- }
-
- protected Template expandMixins(Template tree, final Symbol owner) {
- Type templType = owner.info();
-
- List/*<Tree>*/ newBody = new ArrayList();
- Scope newMembers = new Scope();
-
- Symbol newTemplSymbol = tree.symbol().cloneSymbol();
-
- // Start by copying the statement sequence.
- Tree[] body = tree.body;
- for (int i = 0; i < body.length; ++i) {
- Tree stat = body[i];
- newBody.add(transform(stat));
-
- if (stat.definesSymbol()) {
- Symbol sym = stat.symbol();
- newMembers.enterOrOverload(sym);
- }
- }
-
- Type[] baseTypes = owner.parents();
- global.log("baseTypes for " + Debug.show(owner)
- + " = <" + ArrayApply.toString(baseTypes) + ">");
-
- // Then go over the mixins and mix them in.
- SymbolCloner symbolCloner =
- new SymbolCloner(global.freshNameCreator);
- for (int bcIndex = tree.parents.length - 1; bcIndex > 0; --bcIndex) {
- SymbolSubstTypeMap typeCloner = new SymbolSubstTypeMap();
- Tree bc = tree.parents[bcIndex];
-
- final Symbol bcSym = baseTypes[bcIndex].symbol();
- symbolCloner.owners.put(bcSym, owner);
- symbolCloner.owners.put(bcSym.constructor(), owner);
-
- if ((bcSym.flags & Modifiers.INTERFACE) != 0)
- continue;
-
- assert classDefs.containsKey(bcSym) : bcSym;
- ClassDef bcDef = (ClassDef)classDefs.get(bcSym);
-
- // Create substitution for mixin's type parameters.
- Object[] ts = typeSubst(baseTypes[bcIndex]);
- assert ts.length == 2;
- final Symbol[] tpFormals = (Symbol[])ts[0];
- final Type[] tpActuals = (Type[])ts[1];
- assert tpFormals.length == tpActuals.length;
- Type.Map typeMap = new Type.Map() {
- public Type apply(Type t) {
- Type t1 = t.asSeenFrom(owner.thisType(), bcSym);
- Type t2 = t1.subst(tpFormals, tpActuals);
- return t2;
- }
- };
- typeCloner.insertType(tpFormals, tpActuals);
-
- // Create private fields for mixin's value parameters.
- Tree[][] actuals = getArgsSection(bc);
- assert bcDef.vparams.length == actuals.length;
- for (int s = 0; s < bcDef.vparams.length; ++s) {
- ValDef[] sectionF = bcDef.vparams[s];
- Tree[] sectionA = actuals[s];
-
- assert sectionF.length == sectionA.length;
-
- for (int p = 0; p < sectionF.length; ++p) {
- // We do not need to copy the actual parameters,
- // since they are removed from their original
- // location anyway.
- ValDef formal = sectionF[p];
- Tree actual = sectionA[p];
-
- Symbol memberSymbol =
- symbolCloner.cloneSymbol(formal.symbol(), true);
- memberSymbol.flags &= ~Modifiers.PARAM;
- Type memberType = typeMap.apply(formal.tpe.type());
- memberSymbol.updateInfo(memberType);
-
- Tree memberDef = gen.ValDef(memberSymbol, actual);
- newBody.add(memberDef);
- typeCloner.insertSymbol(formal.symbol(), memberSymbol);
- }
- }
-
- Template mixin = getMixinExpandedTemplate(bcDef.impl, bcSym);
- Type bcType = mixin.type();
- Tree[] mixinBody = mixin.body;
- Map newNames = new HashMap();
-
- // Pass 1: compute members to rename.
- for (int m = 0; m < mixinBody.length; ++m) {
- Tree member = mixinBody[m];
- if (!member.definesSymbol()) continue;
- Symbol symbol = member.symbol();
- Name newName = (Name)newNames.get(symbol.name);
- boolean shadowed = newName == null &&
- newMembers.lookup(symbol.name) != Symbol.NONE;
- if (shadowed && symbol.isDeferred()) continue;
- Symbol clone = symbolCloner.cloneSymbol(symbol, shadowed);
- if (newName != null)
- clone.name = newName;
- else
- newNames.put(symbol.name, clone.name);
- typeCloner.insertSymbol(symbol, clone);
- newMembers.enterOrOverload(clone);
- }
-
- // Pass 2: copy members
- TreeSymbolCloner treeSymbolCloner =
- new TreeSymbolCloner(symbolCloner);
- TreeCloner treeCloner = new TreeCloner(
- global, symbolCloner.clones, typeCloner);
- for (int m = 0; m < mixinBody.length; ++m) {
- Tree member = mixinBody[m];
- if (symbolCloner.clones.containsKey(member.symbol())) {
- treeSymbolCloner.traverse(member);
- newBody.add(treeCloner.transform(member));
- }
- }
+ private void inlineMixinVParams(Symbol[] params, Tree[] args) {
+ for (int i = 0; i < params.length; i++) {
+ Symbol member = cloner.cloneSymbol(params[i], true);
+ member.flags &= ~Modifiers.PARAM;
+ member.flags |= Modifiers.PRIVATE;
+ members.enter(member);
}
-
- // Modify mixin base classes to refer to interfaces instead of
- // real classes.
- Type[] newBaseTypes = new Type[baseTypes.length];
- Tree[] newBaseClasses = new Tree[tree.parents.length];
- newBaseTypes[0] = baseTypes[0];
- newBaseClasses[0] = tree.parents[0];
- for (int i = 1; i < baseTypes.length; ++i) {
- switch (baseTypes[i]) {
- case TypeRef(Type pre, Symbol sym, Type[] args): {
- if (!Modifiers.Helper.isInterface(sym.flags))
- sym = addInterfaces.getInterfaceSymbol(sym);
-
- newBaseClasses[i] =
- gen.mkParentConstr(tree.pos, new Type.TypeRef(pre, sym, args));
- newBaseTypes[i] = new Type.TypeRef(pre, sym, args);
- } break;
-
- default:
- throw global.fail("invalid base class type", baseTypes[i]);
- }
- }
-
- Tree[] fixedBody = (Tree[])newBody.toArray(new Tree[newBody.size()]);
- SuperFixer superFixer = new SuperFixer(
- global, owner, symbolCloner.clones);
- for (int i = 0; i < body.length; ++i) {
- fixedBody[i] = superFixer.transform(fixedBody[i]);
+ // We need two loops because parameters may appear in their types.
+ for (int i = 0; i < params.length; i++) {
+ Symbol member = map.lookupSymbol(params[i]);
+ member.setType(map.apply(member.type()));
+ body.append(gen.ValDef(args[i].pos, member, args[i]));
}
- Template newTree = make.Template(tree.pos, newBaseClasses, fixedBody);
- newTree.setSymbol(newTemplSymbol);
- newTree.setType(Type.compoundType(newBaseTypes, newMembers, owner));
-
- return newTree;
}
- public Tree transform(Tree tree) {
- switch (tree) {
- case ClassDef(_,
- _,
- TypeDef[] tparams,
- ValDef[][] vparams,
- Tree tpe,
- Template impl):
- Symbol sym = tree.symbol();
- if (Modifiers.Helper.isInterface(sym.flags))
- return super.transform(tree);
- else {
- global.log("expanding " + Debug.show(tree.symbol()));
- Tree.ClassDef newClass = (Tree.ClassDef)
- copy.ClassDef(tree,
- sym,
- super.transform(tparams),
- super.transform(vparams),
- super.transform(tpe),
- getMixinExpandedTemplate(impl, sym));
- newClass.symbol().updateInfo(newClass.impl.type);
- return newClass;
- }
-
- default:
- return super.transform(tree);
+ private void inlineMixinMembers(Template mixin) {
+ Scope symbols = mixin.type().members();
+ // The map names is used to implement an all or nothing
+ // strategy for overloaded symbols.
+ Map/*<Name,Name>*/ names = new HashMap();
+ for (SymbolIterator i = symbols.iterator(true); i.hasNext();) {
+ Symbol member = i.next();
+ Name name = (Name)names.get(member.name);
+ boolean shadowed = name == null &&
+ members.lookup(member.name) != Symbol.NONE;
+ Symbol clone = cloner.cloneSymbol(member, shadowed);
+ if (name != null)
+ clone.name = name;
+ else
+ names.put(member.name, clone.name);
+ if (clone.name != member.name) clone.flags &= ~Modifiers.OVERRIDE;
+ clone.setType(clone.type().cloneTypeNoSubst(cloner));
+ members.enterOrOverload(clone);
}
- }
-
- //########################################################################
-
- // Return a hash table associating class definitions to (class) symbols.
- protected static class ClassDefCollector extends Traverser {
- private Map map;
-
- public ClassDefCollector(Map map) {
- this.map = map;
+ // We need two loops because members may appear in their types.
+ for (SymbolIterator i = symbols.iterator(true); i.hasNext();) {
+ Symbol member = map.lookupSymbol(i.next());
+ if (member == null) continue;
+ member.setType(map.applyParams(member.type()));
}
-
- public void traverse(Tree tree) {
- switch(tree) {
- case ClassDef(_, _, _, _, _, _):
- map.put(tree.symbol(), tree);
- break;
-
- default:
- ; // nothing to do
+ cloner.owners.put(mixin.symbol(), template.symbol());
+ final Set clones = new HashSet();
+ TreeSymbolCloner mixinSymbolCloner = new TreeSymbolCloner(cloner) {
+ public Symbol cloneSymbol(Symbol symbol) {
+ Symbol clone = super.cloneSymbol(symbol);
+ clones.add(clone);
+ return clone;
}
- super.traverse(tree);
- }
- }
-
- //########################################################################
- // Private Class - MyTreeCloner
-
- private static class SuperFixer extends Transformer {
-
- private final Symbol clasz;
- private final Map/*<Symbol,Symbol>*/ symbols;
-
- public SuperFixer(Global global, Symbol clasz, Map symbols) {
- super(global);
- this.clasz = clasz;
- this.symbols = symbols;
- }
-
- public Tree transform(Tree tree) {
- switch (tree) {
- case Select(Super(Tree qualifier), _):
- Symbol symbol = (Symbol)symbols.get(tree.symbol());
- if (symbol != null) {
- Tree self = gen.This(((Select)tree).qualifier.pos, clasz);
- return gen.Select(tree.pos, self, symbol);
+ };
+ TreeCloner mixinTreeCloner = new TreeCloner(global, map) {
+ public Tree transform(Tree tree) {
+ switch (tree) {
+ case New(Template template):
+ assert template.parents.length == 1 : tree;
+ assert template.body.length == 0 : tree;
+ Tree apply = template.parents[0];
+ switch (apply) {
+ case Apply(Tree clasz, Tree[] args):
+ args = transform(args);
+ apply = gen.Apply(apply.pos, clasz, args);
+ return gen.New(tree.pos, apply);
+ default:
+ throw Debug.abort("illegal case", tree);
+ }
+ default:
+ return super.transform(tree);
+ }
+ }
+ };
+ for (int i = 0; i < mixin.body.length; i++) {
+ Tree tree = mixin.body[i];
+ // Inline local code and members whose symbol has been cloned.
+ if (!tree.definesSymbol() ||
+ map.lookupSymbol(tree.symbol()) != null) {
+ mixinSymbolCloner.traverse(tree);
+ for (Iterator j = clones.iterator(); j.hasNext();) {
+ Symbol clone = (Symbol)j.next();
+ clone.setType(map.apply(clone.type()));
}
+ clones.clear();
+ body.append(mixinTreeCloner.transform(tree));
}
- return super.transform(tree);
}
}
diff --git a/sources/scalac/transformer/ExpandMixinsPhase.java b/sources/scalac/transformer/ExpandMixinsPhase.java
index 768e7e6d0b..383d5123f6 100644
--- a/sources/scalac/transformer/ExpandMixinsPhase.java
+++ b/sources/scalac/transformer/ExpandMixinsPhase.java
@@ -9,14 +9,52 @@
package scalac.transformer;
-import scalac.*;
-import scalac.checkers.*;
+import java.util.Map;
+import java.util.HashMap;
-import java.util.*;
+import scalac.PhaseDescriptor;
+import scalac.Global;
+import scalac.Unit;
+import scalac.ast.Tree;
+import scalac.ast.Tree.Template;
+import scalac.ast.Traverser;
+import scalac.ast.Transformer;
+import scalac.symtab.Symbol;
+import scalac.symtab.Type;
+import scalac.util.Debug;
+// TODO do not copy hidden members which are not accessible via
+// "super".
+
+/**
+ * A phase to expand mixins using code copying. We assume that links
+ * to outer classes have been made explicit by a previous phase.
+ */
public class ExpandMixinsPhase extends PhaseDescriptor {
- /** Mapping from class symbols to class definitions */
- public Map/*<Symbol,Tree>*/ classDefs = new HashMap();
+
+ //########################################################################
+ // Private Fields
+
+ /** The global environment */
+ private Global global;
+
+ /** A map from classes to their interface */
+ private Map interfaces;
+
+ /** A map from classes to their expanded template */
+ private final Map/*<Symbol,Template>*/ expansions = new HashMap();
+
+ /** A map from classes to their original (unexpanded) template */
+ private final Map/*<Symbol,Template>*/ templates = new HashMap();
+
+ /** A traverser that collects class definitions */
+ private Traverser collector;
+
+ /** A transformer that expands classes that have mixins */
+ private Transformer expander;
+
+ //########################################################################
+ // Public Methods
public String name () {
return "expandmixins";
@@ -31,19 +69,112 @@ public class ExpandMixinsPhase extends PhaseDescriptor {
}
public void apply(Global global) {
- new ExpandMixins(global, this).apply();
+ apply(global, global.units);
+ }
+
+ public void apply(Unit unit) {
+ apply(unit.global, new Unit[] { unit });
}
- public void apply(Unit unit) {
- new ExpandMixins(unit.global, this).apply(unit);
- }
+ public void apply(Global global, Unit[] units) {
+ if (this.global == null) {
+ this.global = global;
+ this.interfaces = global.PHASE.ADDINTERFACES.classToIFace;
+ this.collector = new Collector();
+ this.expander = new Expander(global);
+ }
+ collector.traverse(units);
+ expander.apply(units);
+ assert templates.isEmpty() : templates.keySet();
+ }
- public Checker[] postCheckers(Global global) {
- return new Checker[] {
- new CheckSymbols(global),
- new CheckTypes(global),
- new CheckOwners(global),
- new CheckNames(global)
- };
+ public Type transformInfo(Symbol symbol, Type type) {
+ // !!! make this work and remove *1 in ClassExpander
+ // if (!symbol.isJava() && symbol.isClass() && !symbol.isInterface())
+ // type = getExpandedTemplate(symbol).type();
+ return type;
}
+
+ // !!!
+ // public Checker[] postCheckers(Global global) {
+ // return new Checker[] {
+ // new CheckSymbols(global),
+ // new CheckTypes(global),
+ // new CheckOwners(global),
+ // new CheckNames(global)
+ // };
+ // }
+
+ //########################################################################
+ // Private Methods
+
+ private Template getExpandedTemplate(Symbol clasz) {
+ Template template = (Template)expansions.get(clasz);
+ if (template == null) {
+ template = (Template)templates.remove(clasz);
+ assert template != null : Debug.show(clasz);
+ template = expandTemplate(clasz, expander.transform(template));
+ expansions.put(clasz, template);
+ }
+ return template;
+ }
+
+ private Template expandTemplate(Symbol clasz, Template template) {
+ assert Debug.log("expanding ", clasz);
+ ClassExpander expander = null;
+ Type[] parents = clasz.parents();
+ for (int i = parents.length - 1; i > 0; --i) {
+ Symbol parent = parents[i].symbol();
+ if (parent.isInterface()) continue;
+ if (expander == null)
+ expander = new ClassExpander(global, clasz, template);
+ assert Debug.log("expanding ", clasz, ": inlining ", parent);
+ expander.inlineMixin(i, parents[i], (Symbol)interfaces.get(parent),
+ getExpandedTemplate(parent));
+ }
+ return expander == null ? template : expander.getTemplate();
+ }
+
+ //########################################################################
+ // Private Class - Collector
+
+ private class Collector extends Traverser {
+ public void traverse(Tree tree) {
+ switch(tree) {
+ case ClassDef(_, _, _, _, _, Template template):
+ Symbol clasz = tree.symbol();
+ if (!clasz.isInterface()) templates.put(clasz, template);
+ traverse(template.body);
+ return;
+ case PackageDef(_, Template(_, Tree[] body)):
+ traverse(body);
+ return;
+ }
+ }
+ }
+
+ //########################################################################
+ // Private Class - Expander
+
+ private class Expander extends Transformer {
+ public Expander(Global global) {
+ super(global);
+ }
+ public Tree transform(Tree tree) {
+ switch (tree) {
+ case ClassDef(_, _, _, _, _, _):
+ Symbol clasz = tree.symbol();
+ if (clasz.isInterface()) return super.transform(tree);
+ return gen.ClassDef(tree.pos,clasz,getExpandedTemplate(clasz));
+ case PackageDef(_, _):
+ return super.transform(tree);
+ case Template(_, _):
+ return super.transform(tree);
+ default:
+ return tree;
+ }
+ }
+ }
+
+ //########################################################################
}