*** empty log message ***

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@254 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
schinz 2003-02-19 09:55:54 +00:00
parent 59fd690cce
commit ff60b60d98
8 changed files with 2047 additions and 0 deletions

View File

@ -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;
}
}

View File

@ -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));
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}
}

View File

@ -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)
};
}
}

View File

@ -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);
}
}
}
}

View File

@ -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)
};
}
}