summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
authorschinz <schinz@epfl.ch>2003-05-14 13:08:03 +0000
committerschinz <schinz@epfl.ch>2003-05-14 13:08:03 +0000
commit6be0c19d9efa3567ca63321071593d0a69892bd4 (patch)
tree0c969a9f638b2d898742cfd66f465b2a90e92d44 /sources
parent974fe6069de1fc2c9e7138a3c976a3cc7092233d (diff)
downloadscala-6be0c19d9efa3567ca63321071593d0a69892bd4.tar.gz
scala-6be0c19d9efa3567ca63321071593d0a69892bd4.tar.bz2
scala-6be0c19d9efa3567ca63321071593d0a69892bd4.zip
- complete rewrite of AddInterfaces, to simplif...
- complete rewrite of AddInterfaces, to simplify it and make it compatible with separate compilation (hopefully)
Diffstat (limited to 'sources')
-rw-r--r--sources/scalac/transformer/AddInterfaces.java945
-rw-r--r--sources/scalac/transformer/AddInterfacesPhase.java415
2 files changed, 620 insertions, 740 deletions
diff --git a/sources/scalac/transformer/AddInterfaces.java b/sources/scalac/transformer/AddInterfaces.java
index c4a1eabe9e..20479eeea4 100644
--- a/sources/scalac/transformer/AddInterfaces.java
+++ b/sources/scalac/transformer/AddInterfaces.java
@@ -4,21 +4,24 @@
** /_____/\____/\___/\____/____/ **
\* */
-// $OldId: AddInterfaces.java,v 1.40 2002/11/08 11:56:47 schinz Exp $
// $Id$
+// TODO find a good way to change symbol flags (PRIVATE, DEFERRED,
+// INTERFACE). In particular find how to make sure that the
+// modifications are not made too early, for example before the symbol
+// is cloned.
+
package scalac.transformer;
import scalac.*;
-import scalac.util.*;
+import ch.epfl.lamp.util.*;
import scalac.ast.*;
import scalac.symtab.*;
+import scalac.util.*;
import Tree.*;
import java.util.*;
-// TODO see why lambda-lifted functions end up in the interface
-
/**
* Add, for each class, an interface with the same name, to be used
* later by mixin expansion. More specifically:
@@ -36,793 +39,283 @@ import java.util.*;
* @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;
+class AddInterfaces extends Transformer {
+ protected AddInterfacesPhase phase;
+ protected Definitions defs;
- // 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) {
+ public AddInterfaces(Global global, AddInterfacesPhase phase) {
super(global, global.make);
- classToInterface = descr.classToInterface;
- ifaceToClass = descr.interfaceToClass;
- ifaceMemberToClass = descr.ifaceMemberToClass;
-
- ifaceToClassApplier = new SymbolMapApplier(ifaceToClass);
-
- typeParamsMaps = new HashMap();
- funParamsMaps = new HashMap();
+ this.phase = phase;
+ this.defs = global.definitions;
}
- public void apply() {
- // Phase 1: create all new symbols
- ClassSymCreator creator = new ClassSymCreator();
+ protected LinkedList/*<Pair<Symbol,Symbol>>*/ ownerSubstStack =
+ new LinkedList();
+ protected Pair/*<Symbol,Symbol>*/ ownerSubst = null;
+ protected StackedHashMap identSubst = new StackedHashMap();
+ protected SymbolSubstTypeMap typeSubst = new SymbolSubstTypeMap();
- for (int i = 0; i < global.units.length; ++i)
- creator.traverse(global.units[i].body);
+ protected LinkedList/*<List<Tree>>*/ bodyStack = new LinkedList();
- // Phase 2: transform the tree to add interfaces and use the
- // new symbols where needed.
- super.apply();
- }
+ public Tree[] transform(Tree[] trees) {
+ List newTrees = new ArrayList();
- protected final static Tree.ValDef[][] EMPTY_PARAMS =
- new Tree.ValDef[][]{ new Tree.ValDef[0] };
+ bodyStack.addFirst(newTrees);
- protected void uniqueName(Symbol sym, StringBuffer buf) {
- Symbol owner = sym.owner();
+ for (int i = 0; i < trees.length; ++i)
+ newTrees.add(transform(trees[i]));
- if (owner != Symbol.NONE) {
- uniqueName(owner, buf);
- buf.append('$');
- }
+ bodyStack.removeFirst();
- buf.append(sym.name.toString());
+ return (Tree[]) newTrees.toArray(new Tree[newTrees.size()]);
}
- protected Name uniqueName(Symbol sym) {
- StringBuffer buf = new StringBuffer();
- uniqueName(sym, buf);
- Name newName = Name.fromString(buf.toString());
- if (sym.name.isTypeName()) return newName.toTypeName();
- else if (sym.name.isConstrName()) return newName.toConstrName();
- else return newName;
- }
+ public Tree transform(Tree tree) {
+ // Update tree type, to take into account the new (type)
+ // symbols of enclosing classes / methods.
+ tree.setType(typeSubst.apply(tree.type()));
- protected final static String CLASS_SUFFIX = "$class";
+ if (tree.definesSymbol() && !(tree instanceof ClassDef)) {
+ // Update symbol's owner, if needed.
+ Symbol sym = tree.symbol();
+ if (ownerSubst != null && ownerSubst.fst == sym.owner())
+ sym.setOwner((Symbol)ownerSubst.snd);
+
+ // Update symbol's type. TODO is this needed? Shouldn't
+ // the type of the members be updated in transformInfo.
+ // Here we should only be concerned by the type symbols
+ // appearing in the tree, not in the type.
+ //sym.updateInfo(typeMap.map(sym.info()));
+ }
- protected boolean hasClassSuffix(Name name) {
- return name.toString().endsWith(CLASS_SUFFIX);
- }
+ switch (tree) {
+ case ClassDef(_,_,_,_,_,_): {
+ Symbol sym = tree.symbol();
+ if (phase.needInterface(sym)) {
+ ClassDef classDef = (ClassDef)tree;
+ Symbol ifaceSym = sym;
+ Symbol classSym = phase.getClassSymbol(ifaceSym);
- protected Name className(Name interfaceName) {
- assert !hasClassSuffix(interfaceName) : interfaceName;
+ List/*<Tree>*/ enclosingBody = (List)bodyStack.getFirst();
+ enclosingBody.add(makeInterface(classDef));
- String interfaceStr = interfaceName.toString();
- Name className = Name.fromString(interfaceStr + CLASS_SUFFIX);
- if (interfaceName.isTypeName()) return className.toTypeName();
- else if (interfaceName.isConstrName()) return className.toConstrName();
- else return className;
- }
+ Map classSubst = phase.getClassSubst(classSym);
+ identSubst.push(classSubst);
+ typeSubst.insertSymbol(classSubst);
+ Tree newTree = makeClass(classDef);
+ typeSubst.removeSymbol(classSubst.keySet());
+ identSubst.pop();
- // Modifiers added to interfaces
- // TODO we should put ABSTRACT_CLASS too but that doesn't work now.
- protected int INTERFACE_MODS = Modifiers.INTERFACE | Modifiers.STATIC;
+ return newTree;
+ } else
+ return super.transform(tree);
+ }
- // Modifiers for which we do not create interfaces.
- protected int NO_INTERFACE_MODS =
- (Modifiers.MODUL | Modifiers.SYNTHETIC | Modifiers.JAVA);
+ case DefDef(int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Tree rhs): {
+ Symbol sym = tree.symbol();
+ Symbol owner = sym.owner();
+ Tree newTree;
- protected boolean needInterface(Symbol sym) {
- return (sym != Symbol.NONE)
- && ((sym.primaryConstructorClass().flags & NO_INTERFACE_MODS) == 0);
- }
+ if (owner.isClass() && phase.needInterface(owner)) {
+ Symbol classOwner = phase.getClassSymbol(owner);
+ Map ownerMemberMap = phase.getClassMemberMap(classOwner);
+ Symbol newSym = (Symbol)ownerMemberMap.get(sym);
+ assert newSym != null;
- 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() && !member.isPrimaryConstructor();
- default:
- throw Debug.abort("unknown kind: " + member.kind);
- }
- }
+ global.nextPhase();
+ typeSubst.insertSymbol(sym.typeParams(), newSym.typeParams());
+ identSubst.putAll(sym.valueParams(), newSym.valueParams());
+ global.prevPhase();
- 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;
- }
- }
+ identSubst.push();
+ pushOwnerSubst(sym, newSym);
- 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);
- }
- }
+ newTree = gen.DefDef(newSym, transform(rhs));
- protected Symbol getClassSym(Symbol ifaceSym) {
- assert !hasClassSuffix(ifaceSym.name) : ifaceSym.name;
+ popOwnerSubst();
+ identSubst.pop();
- if (!needInterface(ifaceSym))
- return ifaceSym;
- else {
- assert ifaceToClass.containsKey(ifaceSym);
- return (Symbol)ifaceToClass.get(ifaceSym);
+ typeSubst.removeSymbol(sym.typeParams());
+ } else
+ newTree = super.transform(tree);
+ return newTree;
}
- }
- 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;
+ case This(Ident qualifier): {
+ // Use class symbol for references to "this".
+ Symbol classThisSym = phase.getClassSymbol(qualifier.symbol());
+ return gen.This(tree.pos, classThisSym);
}
- }
- protected Type cloneSymbolsInMethodType(Type type,
- Symbol newOwner,
- 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].setOwner(newOwner);
- newVParams[i].setType(smApplier.apply(newVParams[i].info()));
- symbolMap.put(vparams[i], newVParams[i]);
- }
- return new Type.MethodType(newVParams,
- cloneSymbolsInMethodType(result,
- newOwner,
- smApplier,
- symbolMap));
- }
+ case Select(Super(_), _): {
+ // Use class member symbols for references to "super".
- 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();
- newTParams[i].setOwner(newOwner);
- symbolMap.put(tparams[i], newTParams[i]);
- }
- return new Type.PolyType(newTParams,
- cloneSymbolsInMethodType(result,
- newOwner,
- smApplier,
- symbolMap));
+ Symbol sym = tree.symbol();
+ Symbol classOwner = phase.getClassSymbol(sym.owner());
+ Map ownerMemberMap = phase.getClassMemberMap(classOwner);
+ if (ownerMemberMap != null) {
+ Symbol newSym = (Symbol)ownerMemberMap.get(sym);
+ return gen.Select(((Select)tree).qualifier, newSym);
+ } else
+ return super.transform(tree);
}
- default:
- throw global.fail("unexpected method type: " + Debug.toString(type));
+ case Select(Tree qualifier, _): {
+ Symbol sym = tree.symbol();
+ if (sym.isConstructor()) {
+ // If the constructor now refers to the interface
+ // constructor, use the class constructor instead.
+ Symbol clsSym = sym.primaryConstructorClass();
+ if (phase.needInterface(clsSym))
+ return gen.Select(qualifier,
+ phase.getClassSymbol(clsSym).constructor());
+ else
+ return super.transform(tree);
+ } else
+ return super.transform(tree);
}
- }
- protected static class ThisTypeSubst {
- Symbol fromSym;
- Type toType;
- ThisTypeSubst outer;
- public ThisTypeSubst(Symbol fromSym, Type toType, ThisTypeSubst outer) {
- this.fromSym = fromSym;
- this.toType = toType;
- this.outer = outer;
- }
- public Type apply(Type tp) {
- switch (tp) {
- case ThisType(Symbol sym):
- if (sym == fromSym)
- return toType;
- else if (outer != null)
- return outer.apply(tp);
+ case Ident(_): {
+ Symbol sym = tree.symbol();
+ if (sym.isConstructor()) {
+ // If the constructor now refers to the interface
+ // constructor, use the class constructor instead.
+ Symbol clsSym = sym.primaryConstructorClass();
+ if (phase.needInterface(clsSym))
+ return gen.Ident(phase.getClassSymbol(clsSym).constructor());
+ else
+ return super.transform(tree);
+ } else {
+ Symbol newSym = (Symbol)identSubst.get(tree.symbol());
+ if (newSym != null)
+ return gen.Ident(newSym);
else
- return tp;
- case TypeRef(Type pre, Symbol sym, Type[] args):
- return new Type.TypeRef(apply(pre), sym, apply(args));
- case SingleType(Type pre, Symbol sym):
- return Type.singleType(apply(pre), sym);
- case CompoundType(Type[] parts, Scope members):
- return Type.compoundType(apply(parts), members, tp.symbol());
- case MethodType(Symbol[] vparams, Type result):
- return new Type.MethodType(vparams, apply(result));
- case PolyType(Symbol[] tparams, Type result):
- return new Type.PolyType(tparams, apply(result));
- case OverloadedType(Symbol[] alts, Type[] alttypes):
- return new Type.OverloadedType(alts, apply(alttypes));
- case NoType:
- return tp;
- default:
- throw Debug.abort("unknown type",tp);
+ return super.transform(tree);
}
}
- public Type[] apply(Type[] tps) {
- Type[] newTps = new Type[tps.length];
- for (int i = 0; i < newTps.length; ++i)
- newTps[i] = apply(tps[i]);
- return newTps;
- }
- }
-
- // 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) {
- if (memberGoesInInterface(elem.symbol()))
- ifaceBody.add(mkAbstract(elem));
+ case New(Template templ): {
+ Tree.New newTree = (Tree.New)super.transform(tree);
+ Symbol ifaceSym = newTree.type.unalias().symbol();
+ if (phase.needInterface(ifaceSym)) {
+ Map clsMap = new HashMap();
+ Symbol classSym = phase.getClassSymbol(ifaceSym);
+ clsMap.put(ifaceSym, classSym);
+ clsMap.put(ifaceSym.constructor(), classSym.constructor());
+
+ SymbolSubstTypeMap clsSubst =
+ new SymbolSubstTypeMap(clsMap, Collections.EMPTY_MAP);
+
+ newTree.setType(clsSubst.apply(newTree.type));
+ newTree.templ.setType(clsSubst.apply(newTree.templ.type));
+ Tree.Apply parent = (Tree.Apply)newTree.templ.parents[0];
+ parent.setType(clsSubst.apply(parent.type));
+ parent.fun.setType(clsSubst.apply(parent.fun.type));
}
+ return newTree;
}
- Tree[] parentConstr =
- gen.mkParentConstrs(impl.pos, ifaceSym.nextInfo().parents());
- 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 | INTERFACE_MODS;
- ClassDef interfaceDef = (ClassDef)make.ClassDef(classDef.pos,
- ifaceSym,
- classDef.tparams,
- EMPTY_PARAMS,
- classDef.tpe,
- ifaceTmpl);
- interfaceDef.setType(Type.NoType);
-
- createdIFaces.add(ifaceSym);
-
- return interfaceDef;
- }
-
- protected Type fixClassSymbols(Type type) {
- switch (type) {
- case Type.NoType:
- case ThisType(_):
- return type;
- 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), 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);
+ case Template(_,_): {
+ Symbol sym = tree.symbol();
+ if (sym != Symbol.NONE) {
+ Symbol newDummySymbol = sym.cloneSymbol();
+ pushOwnerSubst(sym, newDummySymbol);
+ Tree newTemplate = super.transform(tree);
+ popOwnerSubst();
+ return newTemplate;
+ } else
+ return super.transform(tree);
}
- }
-
- 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, _): {
- Symbol classSym = getClassSym(tree.symbol());
- return copy.Select(tree, classSym, qualifier);
- }
- case Ident(_): {
- Symbol classSym = getClassSym(tree.symbol());
- return copy.Ident(tree, classSym);
- }
default:
- throw global.fail("unexpected tree",tree);
+ return super.transform(tree);
}
}
- protected LinkedList/*<List<Tree>>*/ bodyStack = new LinkedList();
- protected ThisTypeSubst thisTypeSubst = null;
+ protected Tree makeInterface(ClassDef classDef) {
+ Template classImpl = classDef.impl;
+ Tree[] classBody = classImpl.body;
+ TreeList ifaceBody = new TreeList();
- public Tree[] transform(Tree[] trees) {
- List newTrees = new ArrayList();
+ for (int i = 0; i < classBody.length; ++i) {
+ Tree t = classBody[i];
+ Symbol tSym = t.symbol();
- bodyStack.addFirst(newTrees);
+ if (!t.hasSymbol() || !phase.memberGoesInInterface(tSym))
+ continue;
- for (int i = 0; i < trees.length; ++i)
- newTrees.add(transform(trees[i]));
-
- bodyStack.removeFirst();
-
- return (Tree[]) newTrees.toArray(new Tree[newTrees.size()]);
- }
+ if (tSym.isClass())
+ ifaceBody.append(transform(new Tree[] { t }));
+ else if (tSym.isType())
+ ifaceBody.append(t);
+ else if (tSym.isMethod())
+ ifaceBody.append(gen.DefDef(tSym, Tree.Empty));
+ else
+ throw Debug.abort("don't know what to do with this ", t);
+ }
- public TypeDef[] transform(TypeDef[] ts) {
- return super.transform(ts);
+ return gen.ClassDef(classDef.symbol(), ifaceBody.toArray());
}
- public Tree transform(Tree tree) {
- if (thisTypeSubst != null) {
- if (tree.definesSymbol()) {
- Symbol sym = tree.symbol();
- sym.updateInfo(thisTypeSubst.apply(sym.nextInfo()));
- }
- tree.setType(thisTypeSubst.apply(tree.type()));
- }
-
- switch (tree) {
- case ClassDef(_,
- _,
- 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);
- thisTypeSubst = new ThisTypeSubst(interfaceSym,
- classSym.thisType(),
- thisTypeSubst);
- Tree[] parents = transform(impl.parents);
-
- Tree[] newParents = new Tree[parents.length + 1];
- newParents[0] = parents[0];
- newParents[1] = gen.mkParentConstr(impl.pos, interfaceBaseType);
- 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)) {
- Symbol cSym = (Symbol)ifaceMemberToClass.get(sym);
- member.setSymbol(cSym);
- }
- }
- }
-
- // 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,
- transform(tparams),
- transform(vparams),
- transform(tpe),
- newImpl);
-
- thisTypeSubst = thisTypeSubst.outer;
- popSymbolSubst();
+ protected Tree makeClass(ClassDef classDef) {
+ Symbol ifaceSym = classDef.symbol();
+ Symbol classSym = phase.getClassSymbol(ifaceSym);
- 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);
- }
- }
+ TreeList newClassBody = new TreeList();
+ Template classImpl = classDef.impl;
+ Tree[] classBody = classImpl.body;
- case Template(Tree[] parents, Tree[] body): {
- return copy.Template(tree, transform(parents), transform(body))
- .setType(fixClassSymbols(tree.type));
- }
+ Map classMemberMap = phase.getClassMemberMap(classSym);
+ for (int i = 0; i < classBody.length; ++i) {
+ Tree t = classBody[i];
+ Symbol tSym = t.symbol();
- 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);
- }
+ if (t.hasSymbol() && phase.memberMovesToInterface(tSym))
+ continue;
- case ValDef(_, _, _, _): {
- Symbol sym = tree.symbol();
- Symbol owner = sym.owner();
- if (!sym.isParameter() && ifaceMemberToClass.containsKey(owner)) {
- Symbol newOwner = (Symbol)ifaceMemberToClass.get(owner);
- sym.setOwner(newOwner);
- global.log("new owner for " + Debug.show(sym) + " => " + newOwner);
- }
- return super.transform(tree);
- }
+ Tree newT = transform(t);
- case This(Ident qualifier): {
- Symbol qualSym = qualifier.symbol();
- if (needInterface(qualSym))
- return gen.This(tree.pos, getClassSym(qualSym));
- else
- return super.transform(tree);
- }
+ if (t.hasSymbol() && classMemberMap.containsKey(tSym))
+ newT.setSymbol((Symbol)classMemberMap.get(tSym));
- case Select(Super(_), _): {
- // 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);
+ newClassBody.append(newT);
}
- 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.hasSymbol() && fun.symbol().isPrimaryConstructor())
- return copy.Apply(newTree, tFun, vargs)
- .setType(fixClassSymbols(newTree.type));
- else
- return newTree;
- }
-
- case Apply(Tree fun, Tree[] args): {
- if (fun.hasSymbol() && fun.symbol().isPrimaryConstructor()) {
- fun.setSymbol(getClassSym(fun.symbol()));
- 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.hasSymbol() && 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;
- }
- }
- }
+ Tree[][] oldParentArgs = extractParentArgs(classImpl.parents);
+ Tree[][] parentArgs = new Tree[oldParentArgs.length + 1][];
+ System.arraycopy(oldParentArgs, 0, parentArgs, 0, oldParentArgs.length);
+ parentArgs[oldParentArgs.length] = Tree.EMPTY_ARRAY;
+ global.nextPhase();
+ Type[] newParents = classSym.parents();
+ global.prevPhase();
+ Tree[] newClassParents =
+ gen.mkParentConstrs(classDef.pos, newParents, parentArgs);
+
+ return gen.ClassDef(classSym, newClassParents, newClassBody.toArray());
}
- //////////////////////////////////////////////////////////////////////
-
- // Class
- protected class ClassSymCreator extends Traverser {
- // Mapping from interface type parameters to class type
- // parameters.
- final HashMap/*<Symbol,Symbol>*/ tparamsMap = new HashMap();
-
- 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);
+ protected Tree[][] extractParentArgs(Tree[] parents) {
+ Tree[][] pArgs = new Tree[parents.length][];
+ for (int i = 0; i < parents.length; ++i) {
+ switch(parents[i]) {
+ case Apply(_, Tree[] args): pArgs[i] = args; break;
+ default: throw Debug.abort("unexpected parent constr. ", parents[i]);
}
- return clone;
}
+ return pArgs;
+ }
- protected void makeClassSymbol(Symbol ifaceSym) {
- Symbol classSym = cloneAndMaybeRenameSymbol(ifaceSym);
- ifaceToClass.put(ifaceSym, classSym);
- ifaceToClass.put(ifaceSym.constructor(), classSym.constructor());
- ifaceSym.owner().members().enter(classSym);
- }
+ protected void pushOwnerSubst(Symbol from, Symbol to) {
+ ownerSubstStack.addFirst(ownerSubst);
+ ownerSubst = new Pair(from, to);
+ }
- 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);
- }
-
- 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].setOwner(classConstrSym);
- vparams[i].updateInfo(tparamsSM.apply(vparams[i].info()));
- }
-
- Scope newIFaceMembers = new Scope();
- Scope classMembers = new Scope();
- Scope.SymbolIterator symIt =
- new Scope.UnloadIterator(ifaceSym.members().iterator());
- while (symIt.hasNext()) {
- Symbol ifaceMemberSym = symIt.next();
-
- ifaceMemberSym.updateInfo(tparamsSM.apply(ifaceMemberSym.info()));
-
- if (! memberGoesInInterface(ifaceMemberSym)) {
- if (!ifaceMemberSym.isPrimaryConstructor()) ifaceMemberSym.setOwner(classSym);
- classMembers.enterOrOverload(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;
-
- // 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) {
- newIFaceMembers.enterOrOverload(ifaceMemberSym);
- continue;
- }
-
- if (Modifiers.Helper.isPrivate(ifaceMemberSym.flags)) {
- ifaceMemberSym.name = uniqueName(ifaceMemberSym);
- ifaceMemberSym.flags ^= Modifiers.PRIVATE;
- }
- ifaceMemberSym.flags &= ~Modifiers.PROTECTED;
-
- Symbol classMemberSym;
- if (ifaceToClass.containsKey(ifaceMemberSym))
- classMemberSym = (Symbol)ifaceToClass.get(ifaceMemberSym);
- else
- classMemberSym = cloneAndMaybeRenameSymbol(ifaceMemberSym);
-
- ifaceMemberSym.updateInfo(tparamsSM.apply(ifaceMemberSym.info()));
- classMemberSym.setInfo(tparamsSM.apply(classMemberSym.info()));
-
- Symbol[] vpms = vparams(ifaceMemberSym.nextInfo());
- for (int p = 0; p < vpms.length; ++p)
- vpms[p].updateInfo(tparamsSM.apply(vpms[p].info()));
-
- // Clone parameter symbols for methods.
- if (classMemberSym.isMethod()) {
- Map funSymMap = new HashMap();
- Type newInfo = cloneSymbolsInMethodType(classMemberSym.info(),
- classMemberSym,
- tparamsSM,
- funSymMap);
- if (! funSymMap.isEmpty())
- funParamsMaps.put(classMemberSym, funSymMap);
- }
-
- classMemberSym.setOwner(classSym);
-
- if (ifaceMemberSym.kind == Kinds.CLASS) {
- ifaceToClass.put(ifaceMemberSym, classMemberSym);
- ifaceToClass.put(ifaceMemberSym.constructor(),
- classMemberSym.constructor());
- } else {
- ifaceMemberSym.flags |= Modifiers.DEFERRED;
- ifaceMemberToClass.put(ifaceMemberSym, classMemberSym);
- }
- newIFaceMembers.enterOrOverload(ifaceMemberSym);
- if (!ifaceMemberToClass.containsKey(ifaceMemberSym)
- && ifaceMemberSym.kind != Kinds.CLASS)
- ifaceMemberToClass.put(ifaceMemberSym, classMemberSym);
- classMembers.enterOrOverload(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 |= INTERFACE_MODS;
-
- 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);
- }
- }
+ protected void popOwnerSubst() {
+ ownerSubst = (Pair)ownerSubstStack.removeFirst();
}
}
diff --git a/sources/scalac/transformer/AddInterfacesPhase.java b/sources/scalac/transformer/AddInterfacesPhase.java
index 3aa92b225d..1e2a15a204 100644
--- a/sources/scalac/transformer/AddInterfacesPhase.java
+++ b/sources/scalac/transformer/AddInterfacesPhase.java
@@ -4,29 +4,21 @@
** /_____/\____/\___/\____/____/ **
\* */
-// $OldId: AddInterfacesPhase.java,v 1.9 2002/04/19 10:55:15 schinz Exp $
// $Id$
+// TODO try to use setInfo instead of updateInfo for cloned symbols,
+// to avoid the need to use nextPhase/nextInfo.
+
package scalac.transformer;
import scalac.*;
+import scalac.symtab.*;
import scalac.checkers.*;
+import scalac.util.Name;
import java.util.*;
-
+import scalac.util.Debug;
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";
}
@@ -43,6 +35,78 @@ public class AddInterfacesPhase extends PhaseDescriptor {
new AddInterfaces(global, this).apply();
}
+ public Type transformInfo(Symbol sym, Type tp) {
+ if (sym.isConstructor()
+ && needInterface(sym.primaryConstructorClass())) {
+ // The symbol is a constructor of a class which needs
+ // an interface. All its value arguments have to be
+ // removed.
+ return removeValueParams(tp);
+ } else if (sym.isClass() && !sym.isPackage()) {
+ if (needInterface(sym)) {
+ // Before this phase, the symbol is a class, but after
+ // it will be an interface. Its type has to be changed
+ // so that:
+ //
+ // 1. Java classes are removed from its parents,
+ //
+ // 2. only members which will end up in the
+ // interface are kept, and private ones are made
+ // public and renamed.
+ sym.flags |= Modifiers.INTERFACE;
+
+ Scope.SymbolIterator oldMembersIt =
+ new Scope.UnloadIterator(tp.members().iterator());
+ Scope newMembers = new Scope();
+ while (oldMembersIt.hasNext()) {
+ Symbol member = oldMembersIt.next();
+
+ if (!memberGoesInInterface(member))
+ continue;
+
+ if (member.isPrivate()) {
+ member.name = uniqueName(member);
+ member.flags ^= Modifiers.PRIVATE;
+ } else if (member.isProtected())
+ member.flags ^= Modifiers.PROTECTED;
+
+ newMembers.enterOrOverload(member);
+ }
+
+ LinkedList/*<Type>*/ newParentsLst = new LinkedList();
+ Type[] oldParents = tp.parents();
+ for (int i = 0; i < oldParents.length; ++i) {
+ if (! oldParents[i].symbol().isJava())
+ newParentsLst.addLast(oldParents[i]);
+ }
+ Type[] newParents;
+ if (newParentsLst.size() == oldParents.length)
+ newParents = oldParents;
+ else
+ newParents = (Type[])
+ newParentsLst.toArray(new Type[newParentsLst.size()]);
+ return Type.compoundType(newParents, newMembers, sym);
+ } else {
+ // The symbol is the one of a class which doesn't need
+ // an interface. We need to fix its parents to use
+ // class symbols instead of interface symbols.
+ LinkedList/*<Type>*/ newParentsLst = new LinkedList();
+ Type[] oldParents = tp.parents();
+ for (int i = 0; i < oldParents.length; ++i) {
+ Symbol oldSym = oldParents[i].unalias().symbol();
+ if (needInterface(oldSym))
+ newParentsLst.addLast(getClassSymbol(oldSym).type());
+ else
+ newParentsLst.addLast(oldParents[i]);
+ }
+ Type[] newParents = (Type[])
+ newParentsLst.toArray(new Type[newParentsLst.size()]);
+ return Type.compoundType(newParents, tp.members(), sym);
+ }
+ } else
+ return tp;
+ }
+
public Checker[] postCheckers(Global global) {
return new Checker[] {
new CheckSymbols(global),
@@ -51,4 +115,327 @@ public class AddInterfacesPhase extends PhaseDescriptor {
new CheckNames(global)
};
}
+
+ protected boolean memberGoesInInterface(Symbol member) {
+ return member.isType()
+ || (member.isMethod() && !member.isPrimaryConstructor());
+ }
+
+ protected boolean memberMovesToInterface(Symbol member) {
+ return member.isType();
+ }
+
+ 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 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);
+ Name newName = Name.fromString(buf.toString());
+ if (sym.name.isTypeName()) return newName.toTypeName();
+ else if (sym.name.isConstrName()) return newName.toConstrName();
+ else return newName;
+ }
+
+ // Terminology: in the following code, the symbol which was used
+ // until this phase for the class, and will now be used for the
+ // interface is called the "interface symbol". The symbol created
+ // by this phase for the class is called the "class symbol".
+
+ /** True iff the given class symbol needs an interface. */
+ protected boolean needInterface(Symbol classSym) {
+ assert classSym.isClass()
+ : Debug.toString(classSym) + " is not a class (kind " + classSym.kind + ")";
+ return !(classSym.isJava()
+ || classSym.isModuleClass()
+ || hasInterfaceSymbol(classSym));
+ }
+
+ protected final static String CLASS_SUFFIX = "$class";
+ protected Name className(Name ifaceName) {
+ Name className = Name.fromString(ifaceName.toString() + CLASS_SUFFIX);
+ if (ifaceName.isTypeName()) return className.toTypeName();
+ else if (ifaceName.isConstrName()) return className.toConstrName();
+ else return className;
+ }
+
+ /** Clone symbol and set its owner immediately. */
+ protected Symbol cloneSymbol(Symbol original, Symbol newOwner) {
+ Symbol clone = original.cloneSymbol();
+ clone.setOwner(newOwner);
+ return clone;
+ }
+
+ /** Clone the symbol itself, and if it represents a method, clone
+ * its type and value arguments too, then update the symbol's type
+ * to use these new symbols. Also applies the given substitution
+ * to the cloned symbols' type. */
+ protected Symbol deepCloneSymbol(Symbol original,
+ Symbol newOwner,
+ SymbolSubstTypeMap map) {
+ Symbol clone = cloneSymbol(original, newOwner);
+ if (clone.isMethod()) {
+ Symbol[] tparams = clone.typeParams();
+ Symbol[] newTParams = new Symbol[tparams.length];
+ SymbolSubstTypeMap symMap = new SymbolSubstTypeMap(map);
+ for (int i = 0; i < tparams.length; ++i) {
+ newTParams[i] = cloneSymbol(tparams[i], clone);
+ symMap.insertSymbol(tparams[i], newTParams[i]);
+ }
+
+ Symbol[] vparams = clone.valueParams();
+ Symbol[] newVParams = new Symbol[vparams.length];
+ for (int i = 0; i < vparams.length; ++i) {
+ newVParams[i] = cloneSymbol(vparams[i], clone);
+ newVParams[i].updateInfo(symMap.apply(newVParams[i].info()));
+ symMap.insertSymbol(vparams[i], newVParams[i]);
+ }
+
+ clone.updateInfo(substParams(clone.info(), symMap));
+ }
+ return clone;
+ }
+
+ protected HashMap ifaceToClass = new HashMap();
+ protected HashMap classToIFace = new HashMap();
+
+ /** Return the class symbol corresponding to the given interface
+ * symbol. If the class does not need an interface, return the
+ * given symbol.
+ */
+ protected Symbol getClassSymbol(Symbol ifaceSym) {
+ if (ifaceSym.isPrimaryConstructor())
+ return getClassSymbol(ifaceSym.primaryConstructorClass())
+ .constructor();
+
+ if (!needInterface(ifaceSym))
+ return ifaceSym;
+
+ Symbol classSym = (Symbol)ifaceToClass.get(ifaceSym);
+ if (classSym == null) {
+ classSym = cloneSymbol(ifaceSym, ifaceSym.owner());
+ classSym.name = className(ifaceSym.name);
+ classSym.flags &= ~Modifiers.INTERFACE;
+
+ Symbol ifaceConstrSym = ifaceSym.constructor();
+ Symbol classConstrSym = classSym.constructor();
+ classConstrSym.name = className(ifaceConstrSym.name);
+
+ Scope ifaceOwnerMembers = ifaceSym.owner().members();
+ ifaceOwnerMembers.enter(classSym);
+ ifaceOwnerMembers.enter(classConstrSym);
+
+ // Clone type and value parameters of constructor.
+ Map classSubst = newClassSubst(classSym);
+ Symbol[] tparams = classConstrSym.typeParams();
+ for (int i = 0; i < tparams.length; ++i) {
+ Symbol newParam = cloneSymbol(tparams[i], classConstrSym);
+ classSubst.put(tparams[i], newParam);
+ }
+
+ SymbolSubstTypeMap paramsSubst =
+ new SymbolSubstTypeMap(classSubst, Collections.EMPTY_MAP);
+ // Play it safe and make sure that classSubst won't be
+ // modified anymore.
+ classSubst = Collections.unmodifiableMap(classSubst);
+
+ Symbol[] vparams = classConstrSym.valueParams();
+ for (int i = 0; i < vparams.length; ++i) {
+ vparams[i].setOwner(classConstrSym);
+ vparams[i].updateInfo(paramsSubst.apply(vparams[i].info()));
+ }
+
+ // Clone all members, entering them in the class scope.
+ Map classMembersMap = newClassMemberMap(classSym);
+ Scope classMembers = new Scope();
+ Scope.SymbolIterator ifaceMembersIt =
+ new Scope.UnloadIterator(ifaceSym.members().iterator());
+ while (ifaceMembersIt.hasNext()) {
+ Symbol ifaceMemberSym = ifaceMembersIt.next();
+
+ if (memberMovesToInterface(ifaceMemberSym)
+ || ifaceMemberSym.isPrimaryConstructor())
+ continue;
+
+ Symbol classMemberSym;
+ if (memberGoesInInterface(ifaceMemberSym)) {
+ if (ifaceMemberSym.isPrivate()) {
+ ifaceMemberSym.name = uniqueName(ifaceMemberSym);
+ ifaceMemberSym.flags ^= Modifiers.PRIVATE;
+ } else if (ifaceMemberSym.isProtected())
+ ifaceMemberSym.flags ^= Modifiers.PROTECTED;
+
+ classMemberSym =
+ deepCloneSymbol(ifaceMemberSym, classSym, paramsSubst);
+ ifaceMemberSym.flags |= Modifiers.DEFERRED;
+
+ // TODO substitute symbols in ThisTypes appearing in
+ // the type of the class member
+ classMembersMap.put(ifaceMemberSym, classMemberSym);
+ } else {
+ // Member doesn't go in interface, we just make it
+ // owned by the class.
+ classMemberSym = ifaceMemberSym;
+ classMemberSym.setOwner(classSym);
+ }
+ Type nextMemberTp = classMemberSym.nextInfo();
+ classMemberSym.updateInfo(paramsSubst.apply(nextMemberTp));
+
+ classMembers.enterOrOverload(classMemberSym);
+ if (classMemberSym.isClass())
+ classMembers.enterOrOverload(classMemberSym.constructor());
+ }
+
+ // Give correct type to the class symbol by using class
+ // symbols for its parents, and by adding the interface
+ // among them.
+ Type[] oldClassParents = classSym.parents();
+ int oldParentsCount = oldClassParents.length;
+ Type[] newClassParents = new Type[oldParentsCount + 1];
+ for (int i = 0; i < oldParentsCount; ++i) {
+ switch (oldClassParents[i]) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ Type newTp = Type.typeRef(pre, getClassSymbol(sym), args);
+ newClassParents[i] = paramsSubst.apply(newTp);
+ break;
+ default:
+ throw Debug.abort("unexpected type for parent", oldClassParents[i]);
+ }
+ }
+ newClassParents[oldParentsCount] = paramsSubst.apply(ifaceSym.type());
+ // TODO setInfo cannot be used here because the type then
+ // goes through transformInfo. Maybe setInfo should behave
+ // like updateInfo.
+ classSym.updateInfo(Type.compoundType(newClassParents,
+ classMembers,
+ classSym));
+ classConstrSym.updateInfo(substResType(substParams(classConstrSym.info(),
+ paramsSubst),
+ ifaceSym,
+ classSym));
+
+ ifaceToClass.put(ifaceSym, classSym);
+ classToIFace.put(classSym, ifaceSym);
+ }
+ return classSym;
+ }
+
+ public boolean hasInterfaceSymbol(Symbol classSym) {
+ return classToIFace.containsKey(classSym);
+ }
+
+ public Symbol getInterfaceSymbol(Symbol classSym) {
+ return (Symbol)classToIFace.get(classSym);
+ }
+
+ HashMap/*<Symbol,HashMap>*/ classSubstitutions = new HashMap();
+ protected HashMap newClassSubst(Symbol classSym) {
+ HashMap subst = new HashMap();
+ classSubstitutions.put(classSym, subst);
+ return subst;
+ }
+
+ /** Return symbol substitution for the class (a mapping from the
+ * interface's type and value parameters to the class' equivalent)
+ */
+ public Map getClassSubst(Symbol classSym) {
+ Map classSubst = (Map)classSubstitutions.get(classSym);
+ assert classSubst != null;
+ return classSubst;
+ }
+
+ HashMap/*<Symbol, HashMap>*/ classMemberMaps = new HashMap();
+ protected HashMap newClassMemberMap(Symbol classSym) {
+ HashMap map = new HashMap();
+ classMemberMaps.put(classSym, map);
+ return map;
+ }
+
+ /** Return symbol substitution for the class (a mapping from the
+ * interface's type and value parameters to the class' equivalent)
+ */
+ public Map getClassMemberMap(Symbol classSym) {
+ return (Map)classMemberMaps.get(classSym);
+ }
+
+ /** Substitute type and value arguments in the given type. We
+ * don't use Type.Map here, because it doesn't do what we want, in
+ * particular it doesn't substitute type arguments of PolyTypes */
+ protected Type substParams(Type t, SymbolSubstTypeMap map) {
+ switch (t) {
+ case MethodType(Symbol[] vparams, Type result): {
+ Symbol[] newVParams = new Symbol[vparams.length];
+ for (int i = 0; i < vparams.length; ++i) {
+ newVParams[i] = map.lookupSymbol(vparams[i]);
+ if (newVParams[i] == null) newVParams[i] = vparams[i];
+ }
+ return new Type.MethodType(newVParams, substParams(result, map));
+ }
+
+ case PolyType(Symbol[] tparams, Type result): {
+ Symbol[] newTParams = new Symbol[tparams.length];
+ for (int i = 0; i < tparams.length; ++i) {
+ newTParams[i] = map.lookupSymbol(tparams[i]);
+ if (newTParams[i] == null) newTParams[i] = tparams[i];
+ }
+ return new Type.PolyType(newTParams, substParams(result, map));
+ }
+
+ case TypeRef(Type pre, Symbol sym, Type[] args): {
+ Symbol newSym = map.lookupSymbol(sym);
+ if (newSym == null) newSym = sym;
+ Type[] newArgs = new Type[args.length];
+ for (int i = 0; i < args.length; ++i)
+ newArgs[i] = substParams(args[i], map);
+ return new Type.TypeRef(pre, newSym, newArgs);
+ }
+
+ case SingleType(_, _):
+ case ThisType(_):
+ return t;
+
+ case CompoundType(_,_):
+ // TODO see what to do here.
+ Global.instance.log("WARNING: blindly cloning CompoundType");
+ return t;
+
+ default:
+ throw Debug.abort("unexpected method type", t);
+ }
+ }
+
+ protected Type substResType(Type t, Symbol ifaceSym, Symbol classSym) {
+ switch (t) {
+ case MethodType(Symbol[] vparams, Type result):
+ return new Type.MethodType(vparams,
+ substResType(result, ifaceSym, classSym));
+ case PolyType(Symbol[] tparams, Type result):
+ return new Type.PolyType(tparams,
+ substResType(result, ifaceSym, classSym));
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ assert sym == ifaceSym;
+ return new Type.TypeRef(pre, classSym, args);
+ default:
+ throw Debug.abort("unexpected constructor type");
+ }
+ }
}