summaryrefslogtreecommitdiff
path: root/sources/scalac/symtab/SymbolCloner.java
blob: a1a534fab623894dbe1dd1abeb17c46f3e6d0bd5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    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);
        }
    }}

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