*** 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:
parent
59fd690cce
commit
ff60b60d98
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue