summaryrefslogblamecommitdiff
path: root/sources/scalac/symtab/SymbolCloner.java
blob: a1a534fab623894dbe1dd1abeb17c46f3e6d0bd5 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                                          



                                                                     


                                                                      





                                                                              









                                                                              

                            


                                      

                                     


                                      
                                                 




















                                                                              



                                                                                                          

                                                               

                                                                         



                                  

                                                                
                                                           

                                                     
                                                           


                      


                                                                  

                                                       






















                                                                    

                                                       





                                                     

                                      

















                                                                              


















                                                                              
                                  
 


                                                                              
                       

                       
                      















                                                                 
























                                                                               




                                                                                       

                                                     
                                                        
                
                                     
         
      
 

                                                                              
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $Id$

package scalac.symtab;

import java.util.Map;
import java.util.HashMap;

import scalac.util.Debug;

/**
 * This class implements a symbol cloner. It automatically determines
 * the new owner of cloned symbols, clones their type and keeps track
 * of all cloned symbols. Clone a type means clone all symbol declared
 * in that type (for example parameters of a MethodType).
 */
public class SymbolCloner {

    //########################################################################
    // Public Fields

    /** A table that maps owners of symbols to owners of cloned symbols */
    public final Map/*<Symbol,Symbol*/ owners;

    /** A map<cloned,clone> into which cloned symbols are stored */
    public final Map/*<Symbol,Symbol*/ clones;

    //########################################################################
    // Public Constructor

    /** Initializes a new instance. */
    public SymbolCloner() {
        this(new HashMap());
    }

    /** Initializes a new instance. */
    public SymbolCloner(Map owners) {
        this(owners, new HashMap());
    }

    /** Initializes a new instance. */
    public SymbolCloner(Map owners, Map clones) {
        this.owners = owners;
        this.clones = clones;
    }

    //########################################################################
    // Public Methods - Cloning symbols

    /**
     * Returns the owner for the clone of the given symbol. The
     * default implementation returns the clone of the symbol's owner
     * if that owner has been cloned or else returns the owner
     * associated to the symbol's owner in the owner table.
     */
    public Symbol getOwnerFor(Symbol symbol) {
        Symbol oldowner = symbol.owner();
        Object newowner = clones.get(oldowner);
        if (newowner == null) newowner = owners.get(oldowner);
        assert newowner != null : Debug.show(symbol);
        return (Symbol)newowner;
    }

    /** Clones the given symbol but not its type. */
    public Symbol cloneSymbolWithoutType(Symbol symbol) {
        assert !symbol.isPrimaryConstructor(): Debug.show(symbol);
        assert !symbol.isClassType() || symbol.isCompoundSym(): Debug.show(symbol); // !!! isCompoundSym()
        assert !owners.containsKey(symbol): Debug.show(symbol);
        assert !clones.containsKey(symbol):
            Debug.show(symbol) + " -> " + Debug.show(clones.get(symbol));
        Symbol clone = symbol.cloneSymbol(getOwnerFor(symbol));
        clones.put(symbol, clone);
        return clone;
    }

    /** Clones the given symbols but not their types. */
    public Symbol[] cloneSymbolsWithoutTypes(Symbol[] symbols) {
        if (symbols.length == 0) return Symbol.EMPTY_ARRAY;
        Symbol[] clones = new Symbol[symbols.length];
        for (int i = 0; i < clones.length; i++)
            clones[i] = cloneSymbolWithoutType(symbols[i]);
        return clones;
    }

    /** Clones the given scope but not the type of its members. */
    public Scope cloneScopeWithoutTypes(Scope scope) {
        Scope clone = new Scope();
        for (Scope.SymbolIterator i = scope.iterator();
	     i.hasNext(); ) {
            clone.enterOrOverload(cloneSymbolWithoutType(i.next()));
        }
        return clone;
    }

    /** Clones the given symbol and its type. */
    public Symbol cloneSymbol(Symbol symbol) {
        Symbol clone = cloneSymbolWithoutType(symbol);
        clone.setType(cloneType(symbol.info()));
        return clone;
    }

    /** Clones the given symbols and their types. */
    public Symbol[] cloneSymbols(Symbol[] symbols) {
        Symbol[] clones = cloneSymbolsWithoutTypes(symbols);
        for (int i = 0; i < clones.length; i++)
            clones[i].setType(cloneType(symbols[i].info()));
        return clones;
    }

    /** Clones the given scope and the type of its members. */
    public Scope cloneScope(Scope scope) {
        Scope clone = cloneScopeWithoutTypes(scope);
        for (Scope.SymbolIterator i = scope.iterator();
	     i.hasNext(); ) {
            Symbol member = i.next();
            member.setType(cloneType(member.info()));
        }
        return clone;
    }

    /** Clones the given type. */
    public Type cloneType(Type type) {
        return cloner.apply(type);
    }

    //########################################################################
    // Public Methods - Mapping symbols

    /**
     * Returns the clone of the specified symbol if it has been cloned
     * and the specified symbol otherwise.
     */
    public Symbol mapSymbol(Symbol symbol) {
        Object clone = clones.get(symbol);
        return clone != null ? (Symbol)clone : symbol;
    }

    /** Replaces all cloned symbols by clones in given type. */
    public Type mapType(Type type) {
        return mapper.apply(type);
    }

    //########################################################################
    // Private Method

    private Symbol getCompoundClone(Symbol symbol) {
        assert symbol.isCompoundSym(): Debug.show(symbol);
        assert !owners.containsKey(symbol): Debug.show(symbol);
        assert !clones.containsKey(symbol):
            Debug.show(symbol) + " -> " + Debug.show(clones.get(symbol));
        Symbol owner = (Symbol)clones.get(symbol.owner());
        if (owner == null) owner = (Symbol)owners.get(symbol.owner());
        if (owner == null) owner = symbol.owner();
        Symbol clone = symbol.cloneSymbol(owner);
        clones.put(symbol, clone);
        return clone;
    }

    //########################################################################
    // Private Class - Type mapper

    /** The type mapper Type.Map */
    private final Type.Map mapper = new TypeMapper();
    private class TypeMapper extends Type.Map { public Type apply(Type type) {
        switch (type) {
        case ErrorType:
        case NoType:
        case NoPrefix:
            return type;
        case ThisType(Symbol symbol):
            Symbol clone = (Symbol)clones.get(symbol);
            if (clone == null) return type;
            return Type.ThisType(clone);
        case SingleType(Type prefix, Symbol symbol):
            Symbol clone = (Symbol)clones.get(symbol);
            if (clone == null) return map(type);
            return Type.singleType(apply(prefix), clone);
        case ConstantType(_, _):
            return map(type);
        case TypeRef(Type prefix, Symbol symbol, Type[] args):
            Symbol clone = (Symbol)clones.get(symbol);
            if (clone == null) return map(type);
            return Type.typeRef(apply(prefix), clone, map(args));
        case CompoundType(Type[] parts, Scope members):
            Symbol clone = (Symbol)clones.get(type.symbol());
            // !!! if (clone == null) return map(type);
            if (clone == null) clone = type.symbol();
            return Type.compoundType(map(parts), members, clone);
        case MethodType(Symbol[] vparams, Type result):
            return Type.MethodType(vparams, apply(result));
        case PolyType(Symbol[] tparams, Type result):
            return Type.PolyType(tparams, apply(result));
        case UnboxedType(_):
            return type;
        case UnboxedArrayType(_):
            return map(type);
        default:
            throw Debug.abort("illegal case", type);
        }
    }}

    //########################################################################
    // Private Class - Type cloner

    /** The type cloner Type.Map */
    private final Type.Map cloner = new TypeCloner();
    private class TypeCloner extends TypeMapper { public Type apply(Type type){
        switch (type) {
        case CompoundType(Type[] parts, Scope members):
            Symbol clone = /* !!! getCompoundClone */(type.symbol());
            return Type.compoundType(map(parts), /* !!! cloneScope */(members), clone);
        case MethodType(Symbol[] vparams, Type result):
            Symbol[] clones = cloneSymbols(vparams);
            return Type.MethodType(clones, apply(result));
        case PolyType(Symbol[] tparams, Type result):
            Symbol[] clones = cloneSymbols(tparams);
            return Type.PolyType(clones, apply(result));
        default:
            return super.apply(type);
        }
    }}

    //########################################################################
}