diff options
author | schinz <schinz@epfl.ch> | 2003-02-19 09:55:54 +0000 |
---|---|---|
committer | schinz <schinz@epfl.ch> | 2003-02-19 09:55:54 +0000 |
commit | 8ab0ae13ce49fb8d39a6c9af7873586da4e61c4a (patch) | |
tree | 69bb72f17b10f0f7a6adc553bf5ede8fde279b03 | |
parent | 6cb8bc84c903322e4c87e545c23a648d7950fe9d (diff) | |
download | scala-8ab0ae13ce49fb8d39a6c9af7873586da4e61c4a.tar.gz scala-8ab0ae13ce49fb8d39a6c9af7873586da4e61c4a.tar.bz2 scala-8ab0ae13ce49fb8d39a6c9af7873586da4e61c4a.zip |
*** empty log message ***
-rw-r--r-- | sources/scalac/ast/StrictTreeFactory.java | 317 | ||||
-rw-r--r-- | sources/scalac/ast/SubstTransformer.java | 247 | ||||
-rw-r--r-- | sources/scalac/ast/TreeCopier.java | 91 | ||||
-rw-r--r-- | sources/scalac/symtab/SymbolMapApplier.java | 86 | ||||
-rw-r--r-- | sources/scalac/transformer/AddInterfaces.java | 781 | ||||
-rw-r--r-- | sources/scalac/transformer/AddInterfacesPhase.java | 54 | ||||
-rw-r--r-- | sources/scalac/transformer/ExpandMixins.java | 426 | ||||
-rw-r--r-- | sources/scalac/transformer/ExpandMixinsPhase.java | 45 |
8 files changed, 2047 insertions, 0 deletions
diff --git a/sources/scalac/ast/StrictTreeFactory.java b/sources/scalac/ast/StrictTreeFactory.java new file mode 100644 index 0000000000..c68453424e --- /dev/null +++ b/sources/scalac/ast/StrictTreeFactory.java @@ -0,0 +1,317 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $OldId: StrictTreeFactory.java,v 1.6 2002/04/19 10:57:23 gamboni Exp $ +// $Id$ + +package scalac.ast; + +import scalac.util.Name; +import Tree.*; + +public class StrictTreeFactory extends AbstractTreeCopyFactory { + protected final TreeFactory make; + + public StrictTreeFactory(TreeFactory make) { + this.make = make; + } + + public Tree Bad(Tree tree) { + return tree; + } + + public Tree ClassDef(Tree tree, + int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Template impl) { + ClassDef t = (ClassDef)tree; + tree = make.ClassDef(t.pos, mods, name, tparams, vparams, tpe, impl); + attribute(tree, t); + return tree; + } + + public Tree PackageDef(Tree tree, + Tree packaged, + Template impl) { + PackageDef t = (PackageDef)tree; + tree = make.PackageDef(t.pos, packaged, impl); + attribute(tree, t); + return tree; + } + + public Tree ModuleDef(Tree tree, + int mods, + Name name, + Tree tpe, + Template impl) { + ModuleDef t = (ModuleDef)tree; + tree = make.ModuleDef(t.pos, mods, name, tpe, impl); + attribute(tree, t); + return tree; + } + + public Tree ValDef(Tree tree, + int mods, + Name name, + Tree tpe, + Tree rhs) { + ValDef t = (ValDef)tree; + tree = make.ValDef(t.pos, mods, name, tpe, rhs); + attribute(tree, t); + return tree; + } + + public Tree PatDef(Tree tree, + int mods, + Tree pat, + Tree rhs) { + PatDef t = (PatDef)tree; + tree = make.PatDef(t.pos, mods, pat, rhs); + attribute(tree, t); + return tree; + } + + public Tree DefDef(Tree tree, + int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Tree rhs) { + DefDef t = (DefDef)tree; + tree = make.DefDef(t.pos, mods, name, tparams, vparams, tpe, rhs); + attribute(tree, t); + return tree; + } + + public Tree TypeDef(Tree tree, + int mods, + Name name, + TypeDef[] tparams, + Tree rhs) { + TypeDef t = (TypeDef)tree; + tree = make.TypeDef(t.pos, mods, name, tparams, rhs); + attribute(tree, t); + return tree; + } + + public Tree Import(Tree tree, + Tree expr, + Name[] selectors) { + Import t = (Import)tree; + tree = make.Import(t.pos, expr, selectors); + attribute(tree, t); + return tree; + } + + public Tree CaseDef(Tree tree, + Tree pat, + Tree guard, + Tree body) { + CaseDef t = (CaseDef)tree; + tree = make.CaseDef(t.pos, pat, guard, body); + attribute(tree, t); + return tree; + } + + public Template Template(Tree tree, + Tree[] baseClasses, + Tree[] body) { + Template t = (Template)tree; + Template newTree = make.Template(t.pos, baseClasses, body); + attribute(newTree, t); + return newTree; + } + + public Tree LabelDef(Tree tree, + Tree[] params, + Tree rhs) { + LabelDef t = (LabelDef)tree; + tree = make.LabelDef(t.pos,params,rhs); + attribute(tree,t); + return tree; + } + + public Tree Block(Tree tree, + Tree[] stats) { + Block t = (Block)tree; + tree = make.Block(t.pos, stats); + attribute(tree, t); + return tree; + } + + public Tree Tuple(Tree tree, + Tree[] trees) { + Tuple t = (Tuple)tree; + tree = make.Tuple(t.pos, trees); + attribute(tree, t); + return tree; + } + + public Tree Visitor(Tree tree, + CaseDef[] cases) { + Visitor t = (Visitor)tree; + tree = make.Visitor(t.pos, cases); + attribute(tree, t); + return tree; + } + + public Tree Function(Tree tree, + ValDef[] vparams, + Tree body) { + Function t = (Function)tree; + tree = make.Function(t.pos, vparams, body); + attribute(tree, t); + return tree; + } + + public Tree Assign(Tree tree, + Tree lhs, + Tree rhs) { + Assign t = (Assign)tree; + tree = make.Assign(t.pos, lhs, rhs); + attribute(tree, t); + return tree; + } + + public Tree If(Tree tree, + Tree cond, + Tree thenp, + Tree elsep) { + If t = (If)tree; + tree = make.If(t.pos, cond, thenp, elsep); + attribute(tree, t); + return tree; + } + + public Tree New(Tree tree, + Template templ) { + New t = (New)tree; + tree = make.New(t.pos, templ); + attribute(tree, t); + return tree; + } + + public Tree Typed(Tree tree, + Tree expr, + Tree tpe) { + Typed t = (Typed)tree; + tree = make.Typed(t.pos, expr, tpe); + attribute(tree, t); + return tree; + } + + public Tree TypeApply(Tree tree, + Tree fun, + Tree[] args) { + TypeApply t = (TypeApply)tree; + tree = make.TypeApply(t.pos, fun, args); + attribute(tree, t); + return tree; + } + + public Tree Apply(Tree tree, + Tree fun, + Tree[] args) { + Apply t = (Apply)tree; + tree = make.Apply(t.pos, fun, args); + attribute(tree, t); + return tree; + } + + public Tree This(Tree tree, Tree qualifier) { + This t = (This)tree; + tree = make.This(t.pos, qualifier); + attribute(tree, t); + return tree; + } + + public Tree Super(Tree tree, + Tree tpe) { + Super t = (Super)tree; + tree = make.Super(t.pos, tpe); + attribute(tree, t); + return tree; + } + + public Tree Select(Tree tree, + Tree qualifier, + Name selector) { + Select t = (Select)tree; + tree = make.Select(t.pos, qualifier, selector); + attribute(tree, t); + return tree; + } + + public Tree Ident(Tree tree, + Name name) { + Ident t = (Ident)tree; + tree = make.Ident(t.pos, name); + attribute(tree, t); + return tree; + } + + public Tree Literal(Tree tree, + Object value) { + Literal t = (Literal)tree; + tree = make.Literal(t.pos, value); + attribute(tree, t); + return tree; + } + + public Tree SingletonType(Tree tree, Tree ref) { + SingletonType t = (SingletonType)tree; + tree = make.SingletonType(t.pos, ref); + attribute(tree, t); + return tree; + } + + public Tree SelectFromType(Tree tree, Tree qualifier, Name selector) { + SelectFromType t = (SelectFromType)tree; + tree = make.SelectFromType(t.pos, qualifier, selector); + attribute(tree, t); + return tree; + } + + public Tree FunType(Tree tree, + Tree[] argtpe, + Tree restpe) { + FunType t = (FunType)tree; + tree = make.FunType(t.pos, argtpe, restpe); + attribute(tree, t); + return tree; + } + + public Tree CompoundType(Tree tree, + Tree[] baseTypes, + Tree[] refinements) { + CompoundType t = (CompoundType)tree; + tree = make.CompoundType(t.pos, baseTypes, refinements); + attribute(tree, t); + return tree; + } + + public Tree CovariantType(Tree tree, + Tree clazz) { + CovariantType t = (CovariantType)tree; + tree = make.CovariantType(t.pos, clazz); + attribute(tree, t); + return tree; + } + + public Tree AppliedType(Tree tree, + Tree tpe, + Tree[] args) { + AppliedType t = (AppliedType)tree; + tree = make.AppliedType(t.pos, tpe, args); + attribute(tree, t); + return tree; + } +} diff --git a/sources/scalac/ast/SubstTransformer.java b/sources/scalac/ast/SubstTransformer.java new file mode 100644 index 0000000000..c7802d20d7 --- /dev/null +++ b/sources/scalac/ast/SubstTransformer.java @@ -0,0 +1,247 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $OldId: SubstTransformer.java,v 1.3 2002/04/19 10:55:15 schinz Exp $ +// $Id$ + +package scalac.ast; + +import scalac.*; +import scalac.ast.*; +import scalac.symtab.*; +import scalac.util.*; +import scalac.typechecker.*; +import Tree.*; + +import java.util.*; + +/** + * A transformer which performs symbol or type substitutions. + * + * @author Michel Schinz + * @version 1.0 + */ + +public class SubstTransformer extends Transformer { + protected Map/*<Symbol,Symbol>*/ symbolMap = new HashMap(); + protected SymbolMapApplier smApplier = new SymbolMapApplier(symbolMap); + protected LinkedList/*<Map<Symbol,Symbol>>*/ ssStack = new LinkedList(); + + protected Symbol[] typeMapFormals = Symbol.EMPTY_ARRAY; + protected Type[] typeMapActuals = Type.EMPTY_ARRAY; + protected LinkedList/*<Symbol[]>*/ tmfStack = new LinkedList(); + protected LinkedList/*<Symbol[]>*/ tmaStack = new LinkedList(); + + final protected Type.Map typeMap = + new Type.Map() { + public Type apply(Type t) { + return t.subst(typeMapFormals, typeMapActuals); + } + }; + + protected final TreeCopyFactory simpleCopy; + + public SubstTransformer(Global global, + PhaseDescriptor descr, + TreeFactory make) { + super(global, descr, make, new TCF(make)); + this.simpleCopy = new StrictTreeFactory(make); + + ((TCF)copy).setTransformer(this); + } + + public boolean mustSubstituteSymbol(Tree tree) { + return true; + } + + protected void updateSymbolSubst() { + symbolMap.clear(); + Iterator ssIt = ssStack.iterator(); + while (ssIt.hasNext()) { + Map/*<Symbol,Symbol>*/ map = (Map)ssIt.next(); + symbolMap.putAll(map); + } + } + + public void pushSymbolSubst(Map map) { + ssStack.addLast(map); + updateSymbolSubst(); + } + + public void popSymbolSubst() { + ssStack.removeLast(); + updateSymbolSubst(); + } + + public void clearSymbolSubst() { + ssStack.clear(); + updateSymbolSubst(); + } + + protected void updateTypeSubst() { + assert tmfStack.size() == tmaStack.size(); + + Map/*<Symbol,Type>*/ map = new HashMap(); + Iterator tmfIt = tmfStack.iterator(); + Iterator tmaIt = tmaStack.iterator(); + while (tmfIt.hasNext()) { + assert tmaIt.hasNext(); + Symbol[] formals = (Symbol[]) tmfIt.next(); + Type[] actuals = (Type[]) tmaIt.next(); + assert formals.length == actuals.length; + for (int i = 0; i < formals.length; ++i) + map.put(formals[i], actuals[i]); + } + + typeMapFormals = new Symbol[map.size()]; + typeMapActuals = new Type[map.size()]; + + Set/*<Map.Entry<Symbol,Type>>*/ entries = map.entrySet(); + Iterator entriesIt = entries.iterator(); + int i = 0; + while (entriesIt.hasNext()) { + Map.Entry entry = (Map.Entry)entriesIt.next(); + typeMapFormals[i] = (Symbol)entry.getKey(); + typeMapActuals[i] = (Type)entry.getValue(); + ++i; + } + } + + public void pushTypeSubst(Symbol[] from, Type[] to) { + assert from.length == to.length; + tmfStack.addLast(from); + tmaStack.addLast(to); + updateTypeSubst(); + } + + public void popTypeSubst() { + tmfStack.removeLast(); + tmaStack.removeLast(); + updateTypeSubst(); + } + + public void clearTypeSubst() { + tmfStack.clear(); + tmaStack.clear(); + updateTypeSubst(); + } + + public Tree transform(Tree tree) { + Tree newTree = super.transform(tree); + return syncTree(newTree); + } + + // Update the tree so that: + // 1. names reflect the ones in symbols, + // 2. types reflect the ones in symbols. + // 3. modifiers reflect the ones in symbols. + public Tree syncTree(Tree tree) { + Name newName = null; + Type newType = null; + int newMods = -1; + + if (tree.hasSymbol()) { + Symbol sym = tree.symbol(); + + newName = sym.name; + newType = smApplier.apply(typeMap.apply(sym.nextInfo())); + newMods = sym.flags; + } + + switch (tree) { + case ClassDef(_, // fix Emacs : + _, + Tree.TypeDef[] tparams, + Tree.ValDef[][] vparams, + Tree tpe, + Tree.Template impl) : + return simpleCopy + .ClassDef(tree, newMods, newName, tparams, vparams, tpe, impl); + + case ModuleDef(_, _, Tree tpe, Template impl): + return simpleCopy.ModuleDef(tree, + newMods, + newName, + gen.mkType(tpe.pos, newType), + impl); + + case ValDef(int mods, Name name, Tree tpe, Tree rhs): + return simpleCopy.ValDef(tree, + newMods, + newName, + gen.mkType(tpe.pos, newType), + rhs); + + case DefDef(_, // fix for Emacs : + Name name, + Tree.TypeDef[] tparams, + Tree.ValDef[][] vparams, + Tree tpe, + Tree rhs): + return simpleCopy.DefDef(tree, + newMods, + newName, + tparams, + vparams, + gen.mkType(tpe.pos, newType.resultType()), + rhs); + + case Select(Tree qualifier, _): + return simpleCopy.Select(tree, qualifier, newName); + + case Ident(_): + return simpleCopy.Ident(tree, newName); + + // TODO add a case for TypeDef? + + case Typed(Tree expr, Tree tpe): { + Type newType2 = + smApplier.apply(((Tree.Typed)tree).tpe.type); + return simpleCopy.Typed(tree, + expr, + gen.mkType(tpe.pos, newType2)); + } + + default: + return tree; + } + } + + ////////////////////////////////////////////////////////////////////// + + public static class TCF extends StrictTreeFactory { + protected SubstTransformer transformer; + protected Map/*<Symbol,Symbol>*/ symbolMap; + protected SymbolMapApplier smApplier; + protected Type.Map typeMap; + + public TCF(TreeFactory make) { + super(make); + } + + public void setTransformer(SubstTransformer transformer) { + this.transformer = transformer; + this.symbolMap = transformer.symbolMap; + this.smApplier = transformer.smApplier; + this.typeMap = transformer.typeMap; + } + + public void attribute(Tree newTree, Tree oldTree) { + if (oldTree.hasSymbol()) { + Symbol oldSym = oldTree.symbol(); + + if (transformer.mustSubstituteSymbol(oldTree) + && symbolMap.containsKey(oldSym)) { + newTree.setSymbol((Symbol)symbolMap.get(oldSym)); + } else + newTree.setSymbol(oldTree.symbol()); + } + + newTree.type = smApplier.apply(typeMap.apply(oldTree.type)); + } + } +} diff --git a/sources/scalac/ast/TreeCopier.java b/sources/scalac/ast/TreeCopier.java new file mode 100644 index 0000000000..ad03cd6632 --- /dev/null +++ b/sources/scalac/ast/TreeCopier.java @@ -0,0 +1,91 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $OldId: TreeCopier.java,v 1.17 2002/06/13 12:04:12 schinz Exp $ +// $Id$ + +package scalac.ast; + +import scalac.*; +import scalac.util.Name; +import scalac.symtab.*; +import java.util.*; + +/** + * Superclass for tree copiers. Takes care of duplicating symbols and + * types when needed. + * + * @author Michel Schinz + * @version 1.0 + */ + +public class TreeCopier extends SubstTransformer { + public TreeCopier(Global global, + PhaseDescriptor descr, + TreeFactory make) { + super(global, descr, make); + } + + private boolean inPattern = false; + + // Return true iff tree's symbol must be copied. By default, + // symbols which are defined are copied. + public boolean mustCopySymbol(Tree tree) { + switch (tree) { + case Ident(Name name): + return (inPattern && name.isVariable()) || tree.definesSymbol(); + default: + return tree.definesSymbol(); + } + } + + public Tree copy(Tree tree) { + // Copy all symbols that have to be copied. + Traverser symCopier = new Traverser() { + public void traverse(Tree tree) { + if (tree.hasSymbol()) { + Symbol sym = tree.symbol(); + + if (sym != Symbol.NONE + && mustCopySymbol(tree) + && !symbolMap.containsKey(sym)) { + Symbol newSym = sym.cloneSymbol(); + + if (symbolMap.containsKey(newSym.owner())) + newSym.setOwner((Symbol)symbolMap.get(newSym.owner())); + + symbolMap.put(sym, newSym); + } + } + switch (tree) { + case CaseDef(Tree pat, Tree guard, Tree body): + inPattern = true; traverse(pat); inPattern = false; + traverse(guard); + traverse(body); + break; + default: + super.traverse(tree); + } + } + }; + symCopier.traverse(tree); + + // Copy tree + Tree newTree = transform(tree); + + // Update symbols + Iterator symbolsIt = symbolMap.entrySet().iterator(); + while (symbolsIt.hasNext()) { + Map.Entry symPair = (Map.Entry)symbolsIt.next(); + Symbol oldSym = (Symbol)symPair.getKey(); + Symbol newSym = (Symbol)symPair.getValue(); + + newSym.setInfo(smApplier.apply(typeMap.apply(oldSym.info()))); + } + + return newTree; + } +} diff --git a/sources/scalac/symtab/SymbolMapApplier.java b/sources/scalac/symtab/SymbolMapApplier.java new file mode 100644 index 0000000000..df46d83339 --- /dev/null +++ b/sources/scalac/symtab/SymbolMapApplier.java @@ -0,0 +1,86 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $OldId: SymbolMapApplier.java,v 1.6 2002/04/19 16:41:41 odersky Exp $ +// $Id$ + +package scalac.symtab; + +import scalac.*; +import scalac.symtab.*; +import java.util.*; + + +/** + * Apply a symbol substitution to various data (symbols and types). + * + * @author Michel Schinz + * @version 1.0 + */ + +public class SymbolMapApplier { + protected final Map map; + + public SymbolMapApplier(Map map) { + this.map = map; + } + + public Symbol apply(Symbol sym) { + return map.containsKey(sym) ? (Symbol)map.get(sym) : sym; + } + + public Symbol[] apply(Symbol[] syms) { + Symbol[] newSyms = new Symbol[syms.length]; + for (int i = 0; i < newSyms.length; ++i) + newSyms[i] = apply(syms[i]); + return newSyms; + } + + public Type apply(Type type) { + switch (type) { + case ErrorType: + case AnyType: + case NoType: + return type; + + case ThisType(Symbol sym): + return new Type.ThisType(apply(sym)); + + case TypeRef(Type prefix, Symbol sym, Type[] args): + return new Type.TypeRef(apply(prefix), apply(sym), apply(args)); + + case SingleType(Type pre, Symbol sym): + return Type.singleType(apply(pre), apply(sym)); + + case CompoundType(Type[] parts, Scope members): + return Type.compoundType(apply(parts), members, apply(type.symbol())); + + case MethodType(Symbol[] params, Type restpe): + return new Type.MethodType(apply(params), apply(restpe)); + + case PolyType(Symbol[] tparams, Type restpe): + return new Type.PolyType(apply(tparams), apply(restpe)); + + case OverloadedType(Symbol[] alts, Type[] alttypes): + return new Type.OverloadedType(apply(alts), apply(alttypes)); + + case CovarType(Type result): + return Type.CovarType(apply(result)); + + default: + throw new ApplicationError("unknown type " + type); + } + } + + public Type[] apply(Type[] types) { + Type[] newTypes = new Type[types.length]; + for (int i = 0; i < types.length; ++i) + newTypes[i] = apply(types[i]); + return newTypes; + } + +} diff --git a/sources/scalac/transformer/AddInterfaces.java b/sources/scalac/transformer/AddInterfaces.java new file mode 100644 index 0000000000..65c495a0f3 --- /dev/null +++ b/sources/scalac/transformer/AddInterfaces.java @@ -0,0 +1,781 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $OldId: AddInterfaces.java,v 1.40 2002/11/08 11:56:47 schinz Exp $ +// $Id$ + +package scalac.transformer; + +import scalac.*; +import scalac.util.*; +import scalac.ast.*; +import scalac.symtab.*; +import Tree.*; + +import java.util.*; + +/** + * Add, for each class, an interface with the same name, to be used + * later by mixin expansion. More specifically: + * + * - at the end of the name of every class, the string "$class" is + * added, + * + * - an interface with the original name of the class is created, and + * contains all directly bound members of the class (as abstract + * members), + * + * - the interface is added to the mixin base classes of the class. + * + * @author Michel Schinz + * @version 1.0 + */ + +class AddInterfaces extends SubstTransformer { + /** Mapping from class symbols to their interface symbol. */ + public final Map/*<Symbol,Symbol>*/ classToInterface; + + protected final Map/*<Symbol,Symbol>*/ ifaceToClass; + protected final SymbolMapApplier ifaceToClassApplier; + protected final Map/*<Symbol,Symbol>*/ ifaceMemberToClass; + + // Mapping from class symbol to its type parameters mapping. + protected final Map/*<Symbol,Map<Symbol,Symbol>>*/ typeParamsMaps; + + // Mapping from a class member symbol to its value and type + // parameters mapping. + protected final Map/*<Symbol,Map<Symbol,Symbol>>*/ funParamsMaps; + + protected final Set/*<Symbol>*/ createdIFaces = new HashSet(); + + public AddInterfaces(Global global, AddInterfacesPhase descr) { + super(global, descr, global.make); + classToInterface = descr.classToInterface; + ifaceToClass = descr.interfaceToClass; + ifaceMemberToClass = descr.ifaceMemberToClass; + + ifaceToClassApplier = new SymbolMapApplier(ifaceToClass); + + typeParamsMaps = new HashMap(); + funParamsMaps = new HashMap(); + } + + public void apply() { + // Phase 1: create all new symbols + ClassSymCreator creator = new ClassSymCreator(global); + + for (int i = 0; i < global.units.length; ++i) + creator.traverse(global.units[i].body); + + // Phase 2: transform the tree to add interfaces and use the + // new symbols where needed. + super.apply(); + } + + protected final static Tree.ValDef[][] EMPTY_PARAMS = + new Tree.ValDef[][]{ new Tree.ValDef[0] }; + + protected void uniqueName(Symbol sym, StringBuffer buf) { + Symbol owner = sym.owner(); + + if (owner != Symbol.NONE) { + uniqueName(owner, buf); + buf.append('$'); + } + + buf.append(sym.name.toString()); + } + + protected Name uniqueName(Symbol sym) { + StringBuffer buf = new StringBuffer(); + uniqueName(sym, buf); + return Name.fromString(buf.toString()); + } + + protected final static String CLASS_SUFFIX = "$class"; + + protected boolean hasClassSuffix(Name name) { + return name.toString().endsWith(CLASS_SUFFIX); + } + + protected Name className(Name interfaceName) { + assert !hasClassSuffix(interfaceName) : interfaceName; + + String interfaceStr = interfaceName.toString(); + return Name.fromString(interfaceStr + CLASS_SUFFIX); + } + + // Modifiers for which we do not create interfaces. + protected int NO_INTERFACE_MODS = (Modifiers.MODUL | Modifiers.SYNTHETIC); + + protected boolean needInterface(Symbol sym) { + return (sym.enclClass().flags & NO_INTERFACE_MODS) == 0; + } + + protected boolean memberGoesInInterface(Symbol member) { + switch (member.kind) { + case Kinds.TYPE: case Kinds.ALIAS: + return true; + case Kinds.CLASS: + return needInterface(member); + case Kinds.VAL: + return member.isMethod(); + default: + throw Debug.abort("unknown kind: " + member.kind); + } + } + + protected Type removeValueParams(Type tp) { + switch (tp) { + case MethodType(Symbol[] vparams, Type result): + return new Type.MethodType(Symbol.EMPTY_ARRAY, result); + case PolyType(Symbol[] tps, Type result): + return new Type.PolyType(tps, removeValueParams(result)); + default: + return tp; + } + } + + protected Tree mkAbstract(Tree tree) { + Symbol symbol = tree.symbol(); + + if (symbol.isMethod()) + return gen.DefDef(symbol, Tree.Empty); + else switch (symbol.kind) { + case Kinds.TYPE: case Kinds.ALIAS: + return tree; + case Kinds.CLASS: + return classInterface((ClassDef)tree); + default: + throw new ApplicationError("invalid symbol kind for me", symbol); + } + } + + protected Symbol getClassSym(Symbol ifaceSym) { + assert !hasClassSuffix(ifaceSym.name) : ifaceSym.name; + + if (!needInterface(ifaceSym)) { + return ifaceSym; + } else { + if (!ifaceToClass.containsKey(ifaceSym)) { + Symbol classSym; + + Name ifaceName = ifaceSym.enclClass().fullName(); + classSym = global.definitions.getClass(className(ifaceName)); + if (ifaceSym.isPrimaryConstructor()) { + classSym = classSym.constructor(); + } + + if (classSym == Symbol.NONE && (ifaceSym.flags & Modifiers.JAVA) != 0) { + // Java symbols do not have corresponding classes + return ifaceSym; + } + + assert classSym != Symbol.NONE : ifaceSym; + + ifaceToClass.put(ifaceSym, classSym); + classToInterface.put(classSym, ifaceSym); + } + + return (Symbol)ifaceToClass.get(ifaceSym); + } + } + + protected Symbol[] vparams(Type tp) { + switch (tp) { + case MethodType(Symbol[] vparams, _): + return vparams; + case PolyType(_, Type result): + return vparams(result); + case OverloadedType(_, _): + throw global.fail("can't get vparams of this type", tp); + default: + return Symbol.EMPTY_ARRAY; + } + } + + protected Type cloneSymbolsInMethodType(Type type, + SymbolMapApplier smApplier, + Map symbolMap) { + switch (type) { + case NoType: + case ThisType(_): + case TypeRef(_, _, _): + case SingleType(_, _): + case CompoundType(_, _): + return type; + + case MethodType(Symbol[] vparams, Type result): { + Symbol[] newVParams = new Symbol[vparams.length]; + for (int i = 0; i < vparams.length; ++i) { + newVParams[i] = vparams[i].cloneSymbol(); + newVParams[i].setType(smApplier.apply(newVParams[i].info())); + symbolMap.put(vparams[i], newVParams[i]); + } + return new Type.MethodType(newVParams, + cloneSymbolsInMethodType(result, + smApplier, + symbolMap)); + } + + case PolyType(Symbol[] tparams, Type result): { + Symbol[] newTParams = new Symbol[tparams.length]; + for (int i = 0; i < tparams.length; ++i) { + newTParams[i] = tparams[i].cloneSymbol(); + symbolMap.put(tparams[i], newTParams[i]); + } + return new Type.PolyType(newTParams, + cloneSymbolsInMethodType(result, + smApplier, + symbolMap)); + } + + default: + throw global.fail("unexpected method type: " + Debug.toString(type)); + } + } + + // Return the interface corresponding to the given class. + protected Tree classInterface(ClassDef classDef) { + Template impl = classDef.impl; + Symbol ifaceSym = classDef.symbol(); + + // Create tree for interface. + List/*<Tree>*/ ifaceBody = new ArrayList(); + Tree[] body = impl.body; + for (int i = 0; i < body.length; ++i) { + Tree elem = body[i]; + if (elem.hasSymbol() && elem.symbol().owner() == ifaceSym) { + Symbol sym = elem.symbol(); + if (memberGoesInInterface(elem.symbol())) + ifaceBody.add(mkAbstract(elem)); + } + } + + Tree[] parentConstr = + gen.mkParentConstrs(impl.pos, ifaceSym.nextInfo().parents(), null); + Template ifaceTmpl = + make.Template(impl.pos, + parentConstr, + (Tree[])ifaceBody.toArray(new Tree[ifaceBody.size()])); + ifaceTmpl.setSymbol(impl.symbol().cloneSymbol()); + ifaceTmpl.setType(ifaceSym.nextInfo()); + + int ifaceMods = classDef.mods + | Modifiers.ABSTRACTCLASS + | Modifiers.INTERFACE + | Modifiers.STATIC; + ClassDef interfaceDef = (ClassDef)make.ClassDef(classDef.pos, + ifaceMods, + classDef.name, + classDef.tparams, + EMPTY_PARAMS, + classDef.tpe, + ifaceTmpl); + interfaceDef.setType(Type.NoType); + interfaceDef.setSymbol(ifaceSym); + + createdIFaces.add(ifaceSym); + + return interfaceDef; + } + + protected Type fixClassSymbols(Type type) { + switch (type) { + case Type.NoType: + return type; + case ThisType(Symbol sym): + return new Type.ThisType(getClassSym(sym)); + case TypeRef(Type pre, Symbol sym, Type[] args): + return new Type.TypeRef(fixClassSymbols(pre), getClassSym(sym), args); + case SingleType(Type pre, Symbol sym): + return Type.singleType(fixClassSymbols(pre), getClassSym(sym)); + case CompoundType(Type[] parts, Scope members): + return Type.compoundType(fixClassSymbols(parts), + members, + getClassSym(type.symbol())); + case MethodType(Symbol[] vparams, Type result): + return new Type.MethodType(vparams, fixClassSymbols(result)); + case PolyType(Symbol[] tparams, Type result): + return new Type.PolyType(tparams, fixClassSymbols(result)); + default: + throw global.fail("unexpected type ",type); + } + } + + protected Type[] fixClassSymbols(Type[] types) { + Type[] newTypes = new Type[types.length]; + for (int i = 0; i < types.length; ++i) + newTypes[i] = fixClassSymbols(types[i]); + return newTypes; + } + + protected Tree fixClassSymbols(Tree tree) { + switch (tree) { + case Apply(Tree fun, Tree[] args): + return copy.Apply(tree, fixClassSymbols(fun), args); + case TypeApply(Tree fun, Tree[] args): + return copy.TypeApply(tree, fixClassSymbols(fun), args); + case Select(Tree qualifier, Name selector): { + Symbol classSym = getClassSym(tree.symbol()); + return copy.Select(tree, qualifier, classSym.name).setSymbol(classSym); + } + case Ident(Name name): { + Symbol classSym = getClassSym(tree.symbol()); + return copy.Ident(tree, classSym.name).setSymbol(classSym); + } + default: + throw global.fail("unexpected tree",tree); + } + } + + protected LinkedList/*<List<Tree>>*/ bodyStack = new LinkedList(); + + public Tree[] transform(Tree[] trees) { + List newTrees = new ArrayList(); + + bodyStack.addFirst(newTrees); + + for (int i = 0; i < trees.length; ++i) + newTrees.add(transform(trees[i])); + + bodyStack.removeFirst(); + + return (Tree[]) newTrees.toArray(new Tree[newTrees.size()]); + } + + public TypeDef[] transform(TypeDef[] ts) { + return super.transform(ts); + } + + public Tree transform(Tree tree) { + if (tree.hasSymbol()) { + Symbol sym = tree.symbol(); + if (sym != Symbol.NONE) { + Symbol owner = sym.owner(); + if (ifaceMemberToClass.containsKey(owner)) { + sym.setOwner((Symbol)ifaceMemberToClass.get(owner)); + } + } + } + + switch (tree) { + case ClassDef(int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Template impl) : { + global.log("adding interface for " + tree.symbol() + + " (need one? " + needInterface(tree.symbol()) + ")"); + + Symbol interfaceSym = tree.symbol(); + + if (needInterface(interfaceSym)) { + ClassDef classDef = (ClassDef) tree; + + // First insert interface for class in enclosing body... + if (! createdIFaces.contains(interfaceSym)) { + Tree interfaceDef = classInterface(classDef); + List/*<Tree>*/ enclosingBody = (List)bodyStack.getFirst(); + enclosingBody.add(interfaceDef); + } + + // ...then transform the class. + Symbol classSym = getClassSym(interfaceSym); + + assert typeParamsMaps.containsKey(classSym) : classSym; + Map/*<Symbol,Symbol>*/ tparamsMap = (Map)typeParamsMaps.get(classSym); + SymbolMapApplier tparamsSM = new SymbolMapApplier(tparamsMap); + + // Make the class implement the interface, and make sure + // to use class symbols for base classes. + Type interfaceBaseType = tparamsSM.apply(interfaceSym.type()); + Type[] newBaseTypes; + + // 1. modify type of class symbol + Type newClassInfo; + switch (classSym.nextInfo()) { + case CompoundType(Type[] baseTypes, Scope members): { + newBaseTypes = new Type[baseTypes.length + 1]; + newBaseTypes[0] = fixClassSymbols(baseTypes[0]); + newBaseTypes[1] = interfaceBaseType; + for (int i = 2; i < newBaseTypes.length; ++i) + newBaseTypes[i] = fixClassSymbols(baseTypes[i-1]); + newClassInfo = Type.compoundType(newBaseTypes, members, classSym); + classSym.updateInfo(newClassInfo); + } break; + + default: + throw global.fail("invalid info() for class", classSym); + } + + // 2. modify tree accordingly + pushSymbolSubst(tparamsMap); + Tree[] parents = transform(impl.parents); + + Tree[] newParents = new Tree[parents.length + 1]; + newParents[0] = parents[0]; + newParents[1] = gen.mkParentConstr(impl.pos, interfaceBaseType, null); + for (int i = 2; i < newParents.length; ++i) + newParents[i] = parents[i-1]; + + // Use new member symbols for class members. + Tree[] body = impl.body; + for (int i = 0; i < body.length; ++i) { + Tree member = body[i]; + if (member.hasSymbol()) { + Symbol sym = member.symbol(); + if (sym.kind != Kinds.CLASS + && ifaceMemberToClass.containsKey(sym)) + member.setSymbol((Symbol)ifaceMemberToClass.get(sym)); + } + } + + // Transform body + List newBody = new LinkedList(); + for (int i = 0; i < body.length; ++i) { + switch (body[i]) { + case TypeDef(_, _, _, _): + break; + default: + newBody.add(transform(body[i])); + } + } + Template newImpl = + copy.Template(impl, + newParents, + (Tree[])newBody.toArray(new Tree[newBody.size()])); + newImpl.setType(newClassInfo); + + Tree newTree = + copy.ClassDef(classDef, + classSym.flags, + classSym.name.toTypeName(), + transform(tparams), + transform(vparams), + transform(tpe), + newImpl) + .setSymbol(classSym); + + popSymbolSubst(); + + return newTree; + } else { + // No interface needed, we just adapt the class type + // to use class symbols. + Symbol classSym = interfaceSym; + classSym.updateInfo(fixClassSymbols(classSym.info())); + return super.transform(tree); + } + } + + case Template(Tree[] parents, Tree[] body): { + return copy.Template(tree, transform(parents), transform(body)) + .setType(fixClassSymbols(tree.type)); + } + + case DefDef(_, _, _, _, _, _): { + Symbol sym = tree.symbol(); + if (funParamsMaps.containsKey(sym)) { + Map funParamsMap = (Map)funParamsMaps.get(sym); + pushSymbolSubst(funParamsMap); + Tree newTree = super.transform(tree); + popSymbolSubst(); + return newTree; + } + return super.transform(tree); + } + + case Select(Super(_), Name selector): { + // Use class member symbol for "super" references. + Symbol sym = tree.symbol(); + if (needInterface(sym.classOwner())) { + assert ifaceMemberToClass.containsKey(sym); + Symbol classSym = (Symbol)ifaceMemberToClass.get(sym); + return super.transform(tree).setSymbol(classSym); + } else + return super.transform(tree); + } + + default: { + Tree newTree = super.transform(tree); + + // Use class symbols for constructor calls. + switch (newTree) { + case New(Template templ): + return copy.New(newTree, templ) + .setType(templ.parents[0].type); + + case Apply(TypeApply(Tree fun, Tree[] targs), Tree[] vargs): { + Tree tFun = ((Tree.Apply)newTree).fun; + if (fun.symbol().isPrimaryConstructor()) + return copy.Apply(newTree, tFun, vargs) + .setType(fixClassSymbols(newTree.type)); + else + return newTree; + } + + case Apply(Tree fun, Tree[] args): { + Symbol sym = fun.symbol(); + + if (sym.isPrimaryConstructor()) { + fun.setSymbol(getClassSym(sym)); + fun.setType(fixClassSymbols(fun.type)); + return (copy.Apply(newTree, super.syncTree(fun), args)) + .setType(fixClassSymbols(newTree.type)); + } else + return newTree; + } + + case TypeApply(Tree fun, Tree[] args): { + if (fun.symbol().isPrimaryConstructor()) { + fun.setSymbol(getClassSym(fun.symbol())); + fun.setType(fixClassSymbols(fun.type)); + return (copy.TypeApply(newTree, super.syncTree(fun), args)) + .setType(fixClassSymbols(newTree.type)); + } else + return newTree; + } + default: + return newTree; + } + } + } + } + + ////////////////////////////////////////////////////////////////////// + + // Class + protected class ClassSymCreator extends Traverser { + // Mapping from interface type parameters to class type + // parameters. + final HashMap/*<Symbol,Symbol>*/ tparamsMap = new HashMap(); + + public ClassSymCreator(Global global) { + super(global); + } + + protected Symbol cloneAndMaybeRenameSymbol(Symbol sym) { + assert !sym.isPrimaryConstructor() : sym; + + Symbol clone = sym.cloneSymbol(); + if (clone.kind == Kinds.CLASS) { + clone.name = className(clone.name); + Symbol constrClone = clone.constructor(); + constrClone.name = className(constrClone.name); + } + return clone; + } + + protected void makeClassSymbol(Symbol ifaceSym) { + Symbol classSym = cloneAndMaybeRenameSymbol(ifaceSym); + ifaceToClass.put(ifaceSym, classSym); + ifaceToClass.put(ifaceSym.constructor(), classSym.constructor()); + } + + public void traverse(Tree tree) { + switch(tree) { + case ClassDef(_, _, _, _, _, Template impl): { + Symbol ifaceSym = tree.symbol(); + + if (!needInterface(ifaceSym)) { + super.traverse(impl); + break; + } + + // The class needs an interface. Create new symbols + // for the class itself, its constructor, its type + // parameters and its members. Then modify what was + // the class symbol to turn it into an interface + // symbol. + + // At the end of this part, one inconsistency remains: + // the base types of the new class symbols still refer + // to interface symbols. This is fixed later, when + // symbols exist for *all* classes. + + Symbol ifaceConstrSym = ifaceSym.constructor(); + ifaceConstrSym.updateInfo(removeValueParams(ifaceConstrSym.info())); + + if (! ifaceToClass.containsKey(ifaceSym)) + makeClassSymbol(ifaceSym); + Symbol classSym = (Symbol)ifaceToClass.get(ifaceSym); + Symbol classConstrSym = classSym.constructor(); + + if (ifaceToClass.containsKey(classSym.owner())) { + Symbol newOwner = (Symbol)ifaceToClass.get(classSym.owner()); + classSym.setOwner(newOwner); + classConstrSym.setOwner(newOwner); + } + + Symbol[] ifaceTParams = ifaceSym.typeParams(); + if (ifaceTParams.length > 0) { + for (int i = 0; i < ifaceTParams.length; ++i) { + Symbol classTParam = ifaceTParams[i].cloneSymbol(); + classTParam.setOwner(classConstrSym); + tparamsMap.put(ifaceTParams[i], classTParam); + } + } + assert !typeParamsMaps.containsKey(classSym); + Map cloneMap = new HashMap(); + cloneMap.putAll(tparamsMap); + typeParamsMaps.put(classSym, cloneMap); + + SymbolMapApplier tparamsSM = new SymbolMapApplier(cloneMap); + + classConstrSym.setInfo(tparamsSM.apply(classConstrSym.info())); + Symbol[] vparams = vparams(classConstrSym.nextInfo()); + for (int i = 0; i < vparams.length; ++i) + vparams[i].updateInfo(tparamsSM.apply(vparams[i].info())); + + Scope newIFaceMembers = new Scope(); + Scope classMembers = new Scope(); + Scope.SymbolIterator symIt = ifaceSym.members().iterator(); + while (symIt.hasNext()) { + Symbol ifaceMemberSym = symIt.next(); + + ifaceMemberSym.updateInfo(tparamsSM.apply(ifaceMemberSym.info())); + + if (! memberGoesInInterface(ifaceMemberSym)) { + ifaceMemberSym.setOwner(classSym); + classMembers.enter(ifaceMemberSym); + continue; + } + + // When encountering a constructor of a nested + // class, clone its class to make sure the + // constructor is cloned correctly. + if (ifaceMemberSym.isPrimaryConstructor() + && !ifaceToClass.containsKey(ifaceMemberSym)) { + makeClassSymbol(ifaceMemberSym.primaryConstructorClass()); + } + + // Make private members public and give them a + // unique name. + if (Modifiers.Helper.isPrivate(ifaceMemberSym.flags)) { + ifaceMemberSym.name = uniqueName(ifaceMemberSym); + ifaceMemberSym.flags ^= Modifiers.PRIVATE; + } + ifaceMemberSym.flags &= ~Modifiers.PROTECTED; + + newIFaceMembers.enter(ifaceMemberSym); + + // Type members are moved to the interface. + // Therefore, no symbol has to be created for + // their class equivalent. + if (ifaceMemberSym.kind == Kinds.TYPE + || ifaceMemberSym.kind == Kinds.ALIAS) + continue; + + Symbol[] alternatives = ifaceMemberSym.alternatives(); + Symbol classMemberSym = null; + + for (int a = 0; a < alternatives.length; ++a) { + Symbol iSym = alternatives[a]; + Symbol cSym; + + if (Modifiers.Helper.isPrivate(iSym.flags)) { + iSym.name = uniqueName(iSym); + iSym.flags ^= Modifiers.PRIVATE; + } + iSym.flags &= ~Modifiers.PROTECTED; + + if (ifaceToClass.containsKey(iSym)) + cSym = (Symbol)ifaceToClass.get(iSym); + else + cSym = cloneAndMaybeRenameSymbol(iSym); + + iSym.updateInfo(tparamsSM.apply(iSym.info())); + cSym.setInfo(tparamsSM.apply(cSym.info())); + + Symbol[] vpms = vparams(iSym.nextInfo()); + for (int p = 0; p < vpms.length; ++p) + vpms[p].updateInfo(tparamsSM.apply(vpms[p].info())); + + // Clone parameter symbols for methods. + if (cSym.isMethod()) { + Map funSymMap = new HashMap(); + Type newInfo = cloneSymbolsInMethodType(cSym.info(), + tparamsSM, + funSymMap); + if (! funSymMap.isEmpty()) + funParamsMaps.put(cSym, funSymMap); + } + + cSym.setOwner(classSym); + classMemberSym = (classMemberSym == null + ? cSym + : classMemberSym.overloadWith(cSym)); + + if (iSym.kind == Kinds.CLASS) { + ifaceToClass.put(iSym, cSym); + ifaceToClass.put(iSym.constructor(), cSym.constructor()); + } else { + iSym.flags |= Modifiers.ABSTRACT; + ifaceMemberToClass.put(iSym, cSym); + } + } + if (!ifaceMemberToClass.containsKey(ifaceMemberSym) + && ifaceMemberSym.kind != Kinds.CLASS) + ifaceMemberToClass.put(ifaceMemberSym, classMemberSym); + classMembers.enter(classMemberSym); + } + + switch (classSym.info()) { + case CompoundType(Type[] parts, Scope members): + classSym.setInfo(Type.compoundType(tparamsSM.apply(parts), + classMembers, + classSym)); + break; + + default: + global.fail("unexpected type for class", ifaceSym.info()); + } + + Type cConstrType = classConstrSym.info(); + classConstrSym.updateInfo(cConstrType.subst(new Symbol[]{ifaceSym}, + new Symbol[]{classSym})); + + ifaceSym.flags |= + (Modifiers.ABSTRACTCLASS | Modifiers.INTERFACE | Modifiers.STATIC); + + classToInterface.put(classSym, ifaceSym); + super.traverse(impl); + + if (ifaceTParams.length > 0) + for (int i = 0; i < ifaceTParams.length; ++i) + tparamsMap.remove(ifaceTParams[i]); + + // Remove Java classes from interface base classes. + switch (ifaceSym.info()) { + case CompoundType(Type[] basetypes, Scope members): + ArrayList newBT_L = new ArrayList(basetypes.length); + for (int i = 0; i < basetypes.length; ++i) + if (! basetypes[i].symbol().isJava()) + newBT_L.add(basetypes[i]); + Type[] newBT; + if (newBT_L.size() != basetypes.length) + newBT = (Type[]) newBT_L.toArray(new Type[newBT_L.size()]); + else + newBT = basetypes; + ifaceSym.updateInfo(Type.compoundType(newBT, + newIFaceMembers, + ifaceSym)); + break; + + default: + Debug.abort("unexpected type for class", ifaceSym.info()); + } + } break; + + default: + super.traverse(tree); + } + } + } +} diff --git a/sources/scalac/transformer/AddInterfacesPhase.java b/sources/scalac/transformer/AddInterfacesPhase.java new file mode 100644 index 0000000000..47b30761c0 --- /dev/null +++ b/sources/scalac/transformer/AddInterfacesPhase.java @@ -0,0 +1,54 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $OldId: AddInterfacesPhase.java,v 1.9 2002/04/19 10:55:15 schinz Exp $ +// $Id$ + +package scalac.transformer; + +import scalac.*; +import scalac.checkers.*; +import java.util.*; + + +public class AddInterfacesPhase extends PhaseDescriptor { + /** Mapping from class symbols to their interface symbol. + */ + public final Map/*<Symbol,Symbol>*/ classToInterface = new HashMap(); + + /** Mapping from interface symbols to class symbols. + */ + protected final Map/*<Symbol,Symbol>*/ interfaceToClass = new HashMap(); + + /** Mapping from interface member symbols to class member symbols. + */ + protected final Map/*<Symbol,Symbol>*/ ifaceMemberToClass = new HashMap(); + + public String name () { + return "addinterfaces"; + } + + public String description () { + return "add one interface per class"; + } + + public String taskDescription() { + return "added interfaces"; + } + + public Phase createPhase(Global global) { + return new AddInterfaces(global, this); + } + + public Checker[] postCheckers(Global global) { + return new Checker[] { + new CheckSymbols(global), + new CheckTypes(global), + new CheckOwners(global) + }; + } +} diff --git a/sources/scalac/transformer/ExpandMixins.java b/sources/scalac/transformer/ExpandMixins.java new file mode 100644 index 0000000000..088f392f63 --- /dev/null +++ b/sources/scalac/transformer/ExpandMixins.java @@ -0,0 +1,426 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $OldId: ExpandMixins.java,v 1.24 2002/11/11 16:08:50 schinz Exp $ +// $Id$ + +package scalac.transformer; + +import scalac.*; +import scalac.util.*; +import scalac.ast.*; +import scalac.symtab.*; +import java.util.*; +import java.util.Arrays; +import Tree.*; + +/** + * 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 + */ + +// [...] do not copy hidden members which are not accessible via +// "super" +// [...] handle overloaded symbols + +public class ExpandMixins extends Transformer { + // Mapping from (class) symbols to their definition. + protected final Map/*<Symbol,Tree>*/ classDefs; + + protected final FreshNameCreator freshNameCreator; + protected final Map interfaceToClass; + protected final Map classToInterface; + + protected final static int PRIVATE_FINAL = Modifiers.FINAL | Modifiers.PRIVATE; + + protected final TreeCopier treeCopier; + protected final Definitions defs; + + public ExpandMixins(Global global, ExpandMixinsPhase descr) { + super(global, descr); + defs = global.definitions; + + classToInterface = global.PHASE.ADDINTERFACES.classToInterface; + interfaceToClass = global.PHASE.ADDINTERFACES.interfaceToClass; + + classDefs = descr.classDefs; + + freshNameCreator = global.freshNameCreator; + + treeCopier = new TreeCopier(global, descr, global.make) { + // Substitute symbols refering to this class only. + public boolean mustSubstituteSymbol(Tree tree) { + switch (tree) { + case Ident(_): + case Select(This(_), _): + return true; + + default: + return mustCopySymbol(tree); + } + } + }; + } + + public void apply() { + ClassDefCollector collector = new ClassDefCollector(classDefs); + + 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]); + } + + super.apply(); + } + + protected void typeSubst(Type type, ArrayList f, ArrayList a) { + switch (type) { + case TypeRef(Type pre, Symbol sym, Type[] args): { + Symbol s; + if (interfaceToClass.containsKey(sym)) + s = (Symbol)interfaceToClass.get(sym); + else + s = sym; + + f.addAll(Arrays.asList(s.typeParams())); + a.addAll(Arrays.asList(args)); + typeSubst(pre, f, a); + } break; + default: + ; // nothing to do + } + } + + 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()]) + }; + } + + protected void getArgsSection(Tree tree, List s) { + switch(tree) { + case Apply(Tree fun, Tree[] args): + getArgsSection(fun, s); + s.add(args); + break; + + default: + ; // nothing to do + } + } + + protected Tree[][] getArgsSection(Tree tree) { + List s = new ArrayList(); + getArgsSection(tree, s); + return (Tree[][])s.toArray(new Tree[s.size()][]); + } + + protected Symbol renameSymbol(Map symbolMap, Symbol oldSymbol) { + Name newName = freshNameCreator.newName(oldSymbol.name); + Symbol newSymbol = oldSymbol.cloneSymbol(); + newSymbol.name = newName; + symbolMap.put(oldSymbol, newSymbol); + + return newSymbol; + } + + 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, Symbol owner) { + Type templType = tree.type; + + List/*<Tree>*/ newBody = new ArrayList(); + Scope newMembers = new Scope(); + + Map mixedInSymbols/*<Symbol,Symbol>*/ = new HashMap(); + + 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.hasSymbol()) { + Symbol sym = stat.symbol(); + newMembers.enter(sym); + } + } + + Type[] baseTypes = tree.type.parents(); + global.log("baseTypes = <" + ArrayApply.toString(baseTypes) + ">"); + + // Then go over the mixins and mix them in. + for (int bcIndex = tree.parents.length - 1; bcIndex > 0; --bcIndex) { + Tree bc = tree.parents[bcIndex]; + + Symbol bcSym = baseTypes[bcIndex].symbol(); + Type bcType = bcSym.type(); + + if ((bcSym.flags & Modifiers.INTERFACE) != 0) + continue; + + assert classDefs.containsKey(bcSym) : bcSym; + ClassDef bcDef = (ClassDef)classDefs.get(bcSym); + + Map symbolMap/*<Symbol,Symbol>*/ = new HashMap(); + + // 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) { + return t.subst(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 = + renameSymbol(symbolMap, formal.symbol()); + memberSymbol.setOwner(owner); + Type memberType = typeMap.apply(formal.tpe.type()); + memberSymbol.updateInfo(memberType); + + Tree memberDef = gen.ValDef(memberSymbol, actual); + newBody.add(memberDef); + } + } + + Template mixin = getMixinExpandedTemplate(bcDef.impl, bcSym); + Tree[] mixinBody = mixin.body; + Set/*<Tree>*/ leftOutMembers = new HashSet(); + + // Pass 1: compute members to rename. + for (int m = 0; m < mixinBody.length; ++m) { + Tree member = mixinBody[m]; + + if (!member.hasSymbol()) + continue; + + Symbol memSym = member.symbol(); + Name memName = memSym.name; + + // Check if we have to import this member. To do this, + // we lookup the member both in the template and in + // the mixin, and if the result is the same, we import + // the member (otherwise it means it's shadowed). + + Symbol memSymT = templType.lookupNonPrivate(memName); + Symbol memSymM = bcType.lookupNonPrivate(memName); + + if (memSymT != memSymM) { + if ((memSym.flags & Modifiers.ABSTRACT) != 0) + leftOutMembers.add(member); + else + renameSymbol(symbolMap, memSym); + } + } + + // Pass 2: copy members + for (int m = 0; m < mixinBody.length; ++m) { + Tree member = mixinBody[m]; + + if (leftOutMembers.contains(member)) + continue; + + treeCopier.pushSymbolSubst(symbolMap); + treeCopier.pushTypeSubst(tpFormals, tpActuals); + Tree newMember = treeCopier.copy(member); + treeCopier.popTypeSubst(); + treeCopier.popSymbolSubst(); + + newBody.add(newMember); + + if (newMember.hasSymbol()) { + Symbol sym = newMember.symbol(); + + sym.setOwner(owner); + newMembers.enter(sym); + + mixedInSymbols.put(member.symbol(), newMember.symbol()); + } + } + } + + // 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) && i > 0) { + assert classToInterface.containsKey(sym) : sym; + sym = (Symbol)classToInterface.get(sym); + } + + newBaseClasses[i] = + gen.mkParentConstr(tree.pos, + new Type.TypeRef(pre, sym, args), + null); + newBaseTypes[i] = new Type.TypeRef(pre, sym, args); + } break; + + default: + throw global.fail("invalid base class type", baseTypes[i]); + } + } + + // Use correct symbols for mixed-in members. + SymbolFixer symbolFixer = new SymbolFixer(global, descr, mixedInSymbols); + Tree[] fixedBody = + symbolFixer.transform((Tree[])newBody.toArray(new Tree[newBody.size()])); + 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(int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Template impl): + if (Modifiers.Helper.isInterface(mods)) + return super.transform(tree); + else { + global.log("expanding " + name); + Tree.ClassDef newClass = (Tree.ClassDef) + copy.ClassDef(tree, + mods, + name, + super.transform(tparams), + super.transform(vparams), + super.transform(tpe), + getMixinExpandedTemplate(impl, tree.symbol())); + newClass.symbol().setInfo(newClass.impl.type); + return newClass; + } + + default: + Tree newTree = super.transform(tree); + + switch (newTree) { + case Apply(Select(Tree qualifier, Name selector), Tree[] args): { + Tree fun = ((Tree.Apply)newTree).fun; + Symbol funOwnerSym = fun.symbol().owner(); + Symbol qualSym = qualifier.type.symbol(); + if (! (qualifier instanceof Tree.Super + || qualSym.isSubClass(funOwnerSym))) { + Type ownerTp = funOwnerSym.type(); + Tree castQualifier = + Tree.Apply(Tree.TypeApply(Tree.Select(qualifier, Names.as), + new Tree[] { + gen.mkType(qualifier.pos, ownerTp) + }), + Tree.EMPTY_ARRAY); + return copy.Apply(newTree, + copy.Select(fun, castQualifier, selector), + args); + } else + return newTree; + } + default: + return newTree; + } + } + } + + //######################################################################## + + // 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; + } + + public void traverse(Tree tree) { + switch(tree) { + case ClassDef(_, _, _, _, _, _): + map.put(tree.symbol(), tree); + break; + + default: + ; // nothing to do + } + super.traverse(tree); + } + } + + //######################################################################## + + protected static class SymbolFixer extends Transformer { + protected final Map/*<Symbol,Symbol>*/ mixedInSymbols; + + public SymbolFixer(Global global, PhaseDescriptor descr, Map mixedInSymbols) { + super(global, descr); + this.mixedInSymbols = mixedInSymbols; + } + + public Tree transform(Tree tree) { + switch (tree) { + case Ident(_): { + Symbol sym = tree.symbol(); + if (mixedInSymbols.containsKey(sym)) + return gen.Ident((Symbol)mixedInSymbols.get(sym)); + else + return super.transform(tree); + } + + case Select(Super(Tree tpe), Name selector): { + Symbol sym = tree.symbol(); + if (mixedInSymbols.containsKey(sym)) + return gen.Ident((Symbol)mixedInSymbols.get(sym)); + else + return super.transform(tree); + } + + default: + return super.transform(tree); + } + } + } +} diff --git a/sources/scalac/transformer/ExpandMixinsPhase.java b/sources/scalac/transformer/ExpandMixinsPhase.java new file mode 100644 index 0000000000..fe9bfc259f --- /dev/null +++ b/sources/scalac/transformer/ExpandMixinsPhase.java @@ -0,0 +1,45 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $OldId: ExpandMixinsPhase.java,v 1.8 2002/05/02 10:59:35 schinz Exp $ +// $Id$ + +package scalac.transformer; + +import scalac.*; +import scalac.checkers.*; + +import java.util.*; + +public class ExpandMixinsPhase extends PhaseDescriptor { + /** Mapping from class symbols to class definitions */ + public Map/*<Symbol,Tree>*/ classDefs = new HashMap(); + + public String name () { + return "expandmixins"; + } + + public String description () { + return "expand mixins by code copying"; + } + + public String taskDescription() { + return "expanded mixins"; + } + + public Phase createPhase(Global global) { + return new ExpandMixins(global, this); + } + + public Checker[] postCheckers(Global global) { + return new Checker[] { + new CheckSymbols(global), + new CheckTypes(global), + new CheckOwners(global) + }; + } +} |