diff options
author | paltherr <paltherr@epfl.ch> | 2003-07-27 16:28:06 +0000 |
---|---|---|
committer | paltherr <paltherr@epfl.ch> | 2003-07-27 16:28:06 +0000 |
commit | b7378219e2ac7ac9144a7bde821b919034b5d4fa (patch) | |
tree | 19d63a78381b82db2bae837215b872f398d6a154 /sources/scalac/transformer | |
parent | 59f320de1d5f50adc491dcc8cefd71334f3129dd (diff) | |
download | scala-b7378219e2ac7ac9144a7bde821b919034b5d4fa.tar.gz scala-b7378219e2ac7ac9144a7bde821b919034b5d4fa.tar.bz2 scala-b7378219e2ac7ac9144a7bde821b919034b5d4fa.zip |
- Rewrote and reorganized several parts.
- Fixed some bugs (missing clones, wrong owners, missing sharing (param
symbols), this types, new of mixed in mixin, ...).
Diffstat (limited to 'sources/scalac/transformer')
-rw-r--r-- | sources/scalac/transformer/ExpandMixins.java | 480 | ||||
-rw-r--r-- | sources/scalac/transformer/ExpandMixinsPhase.java | 163 |
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; + } + } + } + + //######################################################################## } |