]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/types/TMetaVar.java
migrated to svn revision 33108
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / types / TMetaVar.java
1 package org.simantics.scl.compiler.types;
2
3 import java.util.ArrayList;
4
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
6 import org.simantics.scl.compiler.environment.Environment;
7 import org.simantics.scl.compiler.internal.types.HashCodeUtils;
8 import org.simantics.scl.compiler.internal.types.TypeHashCodeContext;
9 import org.simantics.scl.compiler.internal.types.ast.TVarAst;
10 import org.simantics.scl.compiler.internal.types.ast.TypeAst;
11 import org.simantics.scl.compiler.types.exceptions.KindUnificationException;
12 import org.simantics.scl.compiler.types.exceptions.UnificationException;
13 import org.simantics.scl.compiler.types.kinds.KMetaVar;
14 import org.simantics.scl.compiler.types.kinds.Kind;
15 import org.simantics.scl.compiler.types.kinds.Kinds;
16 import org.simantics.scl.compiler.types.util.Polarity;
17 import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
18
19 import gnu.trove.map.hash.THashMap;
20 import gnu.trove.set.hash.THashSet;
21
22
23
24 /**
25  * A meta-variable, a type that is currently unknown. This class
26  * should occur only during type inference. Method removeMetaVars
27  * can be used to remove all instances of TMetaVar from the type.
28  * 
29  * @author Hannu Niemistö
30  */
31 public class TMetaVar extends Type {
32     public static final TMetaVar[] EMPTY_ARRAY = new TMetaVar[0];
33     public static final boolean DEBUG = false;
34     
35     Type ref = null;
36     Type skeletonRef = null;
37     Polarity polarity = Polarity.NO_POLARITY;
38     private Kind kind;
39     private TMetaVarListener listener;
40     
41     public static abstract class TMetaVarListener {
42         private Object prev; // TMetaVarListener or TMetaVar
43         private TMetaVarListener next;
44         
45         public abstract void notifyAboutChange();
46         
47         public void remove() {
48             if(prev == null)
49                 return; // Not added or not anymore listening TMetaVar
50             if(prev instanceof TMetaVar)
51                 ((TMetaVar)prev).listener = next;
52             else
53                 ((TMetaVarListener)prev).next = next;
54             if(next != null) {
55                 next.prev = prev;
56                 next = null;
57             }
58             prev = null;
59         }
60     }
61     
62     TMetaVar(Kind kind) {
63         this.kind = kind;
64     }
65     
66     TMetaVar(Kind kind, Polarity polarity) {
67         this.kind = kind;
68         this.polarity = polarity;
69     }
70     
71     public Kind getKind() {
72         if(kind instanceof KMetaVar)
73             kind = Kinds.canonical(kind);
74         return kind;        
75     }
76     
77     @Override
78     public Type replace(TVar var, Type replacement) {
79         if(ref == null)
80             return this;
81         else {
82             Type newRef = ref.replace(var, replacement);
83             if(newRef != ref)
84                 return newRef;
85             else
86                 // We could also return newRef here, but in this way
87                 // we don't have to copy so many parent types.
88                 return this;
89         }
90     }
91
92     @Override
93     public TypeAst toTypeAst(TypeUnparsingContext context) {
94         if(ref == null)
95             return new TVarAst(/*polarity.getSymbol() +*/ context.getName(this));
96         else
97             return ref.toTypeAst(context);
98     }
99     
100     @Override
101     public int hashCode() {
102         if(ref == null)
103             return System.identityHashCode(this);
104         else
105             return ref.hashCode();
106     }
107     
108     @Override
109     public void updateHashCode(TypeHashCodeContext context) {
110         if(ref == null)
111             context.append(System.identityHashCode(this));
112         else
113             ref.updateHashCode(context);
114     }
115
116     @Override
117     public void collectFreeVars(ArrayList<TVar> vars) {
118         if(ref != null)
119             ref.collectFreeVars(vars);
120     }
121     
122     @Override
123     public void collectMetaVars(ArrayList<TMetaVar> vars) {
124         if(ref == null)
125             vars.add(this);
126         else
127             ref.collectMetaVars(vars);
128     }
129     
130     @Override
131     public void collectMetaVars(THashSet<TMetaVar> vars) {
132         if(ref == null)
133             vars.add(this);
134         else
135             ref.collectMetaVars(vars);
136     }
137     
138     @Override
139     public void collectEffectMetaVars(ArrayList<TMetaVar> vars) {
140         if(ref != null)
141             ref.collectEffectMetaVars(vars);
142     }
143
144     public void setRef(Type type) throws UnificationException {
145         if(DEBUG)
146             System.out.println("setRef " + System.identityHashCode(this) + " -> " + type);
147         if(ref != null)
148             throw new InternalCompilerError("Method setRef should be called only for unbound meta variables.");
149         if(type.contains(this))
150             throw new UnificationException(this, type);
151         ref = type;
152         if(polarity != Polarity.NO_POLARITY)
153             type.addPolarity(polarity);
154         if(skeletonRef != null) {
155             Type skeleton = skeletonRef;
156             skeletonRef = null;
157             Skeletons.unifySkeletons(skeleton, type);
158         }
159         fireNotifyAboutChange();
160     }
161     
162     public Type getRef() {
163         return ref;
164     }
165     
166     @Override
167     public boolean contains(TMetaVar other) {
168         if(ref != null)
169             return ref.contains(other);
170         else if(skeletonRef != null)
171             return skeletonRef.contains(other);
172         else
173             return this == other;
174     }
175     
176     @Override
177     public Type convertMetaVarsToVars() {
178         if(ref == null) {
179             if(kind == Kinds.EFFECT && !polarity.isNegative())
180                 ref = Types.NO_EFFECTS;
181             else
182                 ref = Types.var(getKind());
183             return ref;
184         }
185         else
186             return ref.convertMetaVarsToVars();
187     }
188
189     @Override
190     public boolean isGround() {
191         if(ref == null)
192             return false;
193         else
194             return ref.isGround();
195     }
196
197         public Kind inferKind(Environment context) throws KindUnificationException {
198             return Kinds.metaVar();
199     }
200
201     @Override
202     public boolean containsMetaVars() {
203         if(ref == null)
204             return true;
205         else
206             return ref.containsMetaVars();
207     }
208
209     @Override
210     public void toName(TypeUnparsingContext context, StringBuilder b) {
211         if(ref != null)
212             ref.toName(context, b);
213         else
214             b.append(context.getName(this));
215     }
216     
217     @Override
218     public int getClassId() {
219         return METAVAR_ID;
220     }
221  
222     @Override
223     public boolean isMaximal() {
224         return ref != null && ref.isMaximal(); 
225     }
226     
227     @Override
228     public boolean isMinimal() {
229         return ref != null && ref.isMinimal();
230     }
231
232     @Override
233     public void addPolarity(Polarity polarity) {        
234         if(ref != null)
235             ref.addPolarity(polarity);
236         else
237             this.polarity = this.polarity.add(polarity);
238     }
239
240     public Polarity getPolarity() {
241         return polarity;
242     }
243     
244     @Override
245     public void collectConcreteEffects(ArrayList<TCon> concreteEffects) {
246         if(ref != null)
247             ref.collectConcreteEffects(concreteEffects);
248     }
249
250     @Override
251     public Type head() {
252         if(ref != null)
253             return ref.head();
254         else
255             return this;
256     }
257
258     @Override
259     public Type copySkeleton(THashMap<TMetaVar, TMetaVar> metaVarMap) {
260         if(ref != null)
261             return ref.copySkeleton(metaVarMap);
262         else {
263             TMetaVar result = metaVarMap.get(this);
264             if(result == null) {
265                 result = new TMetaVar(kind, polarity);
266                 metaVarMap.put(this, result);
267             }
268             return result;
269         }
270     }
271
272     public void setSkeletonRef(Type type) throws UnificationException {
273         if(DEBUG)
274             System.out.println("setSkeletonRef " +  System.identityHashCode(this) + " -> " + type);
275         if(ref != null || skeletonRef != null)
276             throw new InternalCompilerError("Method setRef should be called only for unbound meta variables.");
277         if(type.contains(this))
278             throw new UnificationException(this, type);
279         this.skeletonRef = type;
280         fireNotifyAboutChange();
281     }
282     
283     @Override
284     public int hashCode(int hash) {
285         if(ref == null)
286             return HashCodeUtils.update(hash, System.identityHashCode(this));
287         else
288             return ref.hashCode(hash);
289     }
290     
291     @Override
292     public int hashCode(int hash, TVar[] boundVars) {
293         if(ref == null)
294             return HashCodeUtils.update(hash, System.identityHashCode(this));
295         else
296             return ref.hashCode(hash, boundVars);
297     }
298     
299     @Override
300     public boolean equalsCanonical(Type other) {
301         return this == other;
302     }
303     
304     @Override
305     public Type canonical() {
306         if(ref == null)
307             return this;
308         else
309             return ref = ref.canonical();
310     }
311     
312     public void addListener(TMetaVarListener newListener) {
313         if(DEBUG)
314             System.out.println("addListener " + System.identityHashCode(this));
315         newListener.next = listener;
316         newListener.prev = this;
317         if(listener != null)
318             listener.prev = newListener;
319         listener = newListener;
320     }
321     
322     private void fireNotifyAboutChange() {
323         if(DEBUG)
324             System.out.println("fireNotifyAboutChange " + System.identityHashCode(this) + " " + ref);
325         TMetaVarListener cur = listener;
326         listener = null;
327         while(cur != null) {
328             if(DEBUG)
329                 System.out.println("    call listener");
330             cur.prev = null; // This prevents TMetaVarListener.remove from doing anything
331             cur.notifyAboutChange();
332             TMetaVarListener next = cur.next;
333             cur.next = null;
334             cur = next;
335         }
336     }
337     
338     public TMetaVarListener getLatestListener() {
339         return listener;
340     }
341
342     @Override
343     public Kind getKind(Environment context) {
344         return kind;
345     }
346 }