From 8ab0ae13ce49fb8d39a6c9af7873586da4e61c4a Mon Sep 17 00:00:00 2001 From: schinz Date: Wed, 19 Feb 2003 09:55:54 +0000 Subject: *** empty log message *** --- sources/scalac/transformer/AddInterfaces.java | 781 +++++++++++++++++++++ sources/scalac/transformer/AddInterfacesPhase.java | 54 ++ sources/scalac/transformer/ExpandMixins.java | 426 +++++++++++ sources/scalac/transformer/ExpandMixinsPhase.java | 45 ++ 4 files changed, 1306 insertions(+) create mode 100644 sources/scalac/transformer/AddInterfaces.java create mode 100644 sources/scalac/transformer/AddInterfacesPhase.java create mode 100644 sources/scalac/transformer/ExpandMixins.java create mode 100644 sources/scalac/transformer/ExpandMixinsPhase.java (limited to 'sources/scalac/transformer') 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/**/ classToInterface; + + protected final Map/**/ ifaceToClass; + protected final SymbolMapApplier ifaceToClassApplier; + protected final Map/**/ ifaceMemberToClass; + + // Mapping from class symbol to its type parameters mapping. + protected final Map/*>*/ typeParamsMaps; + + // Mapping from a class member symbol to its value and type + // parameters mapping. + protected final Map/*>*/ funParamsMaps; + + protected final Set/**/ 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/**/ 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/*>*/ 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/**/ enclosingBody = (List)bodyStack.getFirst(); + enclosingBody.add(interfaceDef); + } + + // ...then transform the class. + Symbol classSym = getClassSym(interfaceSym); + + assert typeParamsMaps.containsKey(classSym) : classSym; + Map/**/ 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/**/ 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/**/ classToInterface = new HashMap(); + + /** Mapping from interface symbols to class symbols. + */ + protected final Map/**/ interfaceToClass = new HashMap(); + + /** Mapping from interface member symbols to class member symbols. + */ + protected final Map/**/ 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/**/ 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/**/ f = new ArrayList(); + ArrayList/**/ 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/**/ 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/**/ newBody = new ArrayList(); + Scope newMembers = new Scope(); + + Map mixedInSymbols/**/ = 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/**/ = 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/**/ 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/**/ 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/**/ 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) + }; + } +} -- cgit v1.2.3