]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/types/TMetaVar.java
Merge "List the unsatisfied dependencies in CanvasContext"
[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 void updateHashCode(TypeHashCodeContext context) {
102         if(ref == null)
103             context.append(System.identityHashCode(this));
104         else
105             ref.updateHashCode(context);
106     }
107
108     @Override
109     public void collectFreeVars(ArrayList<TVar> vars) {
110         if(ref != null)
111             ref.collectFreeVars(vars);
112     }
113     
114     @Override
115     public void collectMetaVars(ArrayList<TMetaVar> vars) {
116         if(ref == null)
117             vars.add(this);
118         else
119             ref.collectMetaVars(vars);
120     }
121     
122     @Override
123     public void collectMetaVars(THashSet<TMetaVar> vars) {
124         if(ref == null)
125             vars.add(this);
126         else
127             ref.collectMetaVars(vars);
128     }
129     
130     @Override
131     public void collectEffectMetaVars(ArrayList<TMetaVar> vars) {
132         if(ref != null)
133             ref.collectEffectMetaVars(vars);
134     }
135
136     public void setRef(Type type) throws UnificationException {
137         if(type instanceof TMetaVar && ((TMetaVar)type).ref != null)
138             throw new InternalCompilerError("Not canonical!");
139         if(type == this)
140             throw new InternalCompilerError("Illegal setRef");
141         if(DEBUG)
142             System.out.println("setRef " + System.identityHashCode(this) + " -> " + type);
143         if(ref != null)
144             throw new InternalCompilerError("Method setRef should be called only for unbound meta variables.");
145         if(type.contains(this))
146             throw new UnificationException(this, type);
147         ref = type;
148         if(polarity != Polarity.NO_POLARITY)
149             type.addPolarity(polarity);
150         if(skeletonRef != null) {
151             Type skeleton = skeletonRef;
152             skeletonRef = null;
153             Skeletons.unifySkeletons(skeleton, type);
154         }
155         fireNotifyAboutChange();
156     }
157     
158     public Type getRef() {
159         return ref;
160     }
161     
162     @Override
163     public boolean contains(TMetaVar other) {
164         if(ref != null)
165             return ref.contains(other);
166         else if(skeletonRef != null)
167             return skeletonRef.contains(other);
168         else
169             return this == other;
170     }
171     
172     @Override
173     public Type convertMetaVarsToVars() {
174         if(ref == null) {
175             if(kind == Kinds.EFFECT && !polarity.isNegative())
176                 ref = Types.NO_EFFECTS;
177             else
178                 ref = Types.var(getKind());
179             return ref;
180         }
181         else
182             return ref.convertMetaVarsToVars();
183     }
184
185     @Override
186     public boolean isGround() {
187         if(ref == null)
188             return false;
189         else
190             return ref.isGround();
191     }
192
193         public Kind inferKind(Environment context) throws KindUnificationException {
194             return Kinds.metaVar();
195     }
196
197     @Override
198     public boolean containsMetaVars() {
199         if(ref == null)
200             return true;
201         else
202             return ref.containsMetaVars();
203     }
204
205     @Override
206     public void toName(TypeUnparsingContext context, StringBuilder b) {
207         if(ref != null)
208             ref.toName(context, b);
209         else
210             b.append(context.getName(this));
211     }
212     
213     @Override
214     public int getClassId() {
215         return METAVAR_ID;
216     }
217  
218     @Override
219     public boolean isMaximal() {
220         return ref != null && ref.isMaximal(); 
221     }
222     
223     @Override
224     public boolean isMinimal() {
225         return ref != null && ref.isMinimal();
226     }
227
228     @Override
229     public void addPolarity(Polarity polarity) {        
230         if(ref != null)
231             ref.addPolarity(polarity);
232         else
233             this.polarity = this.polarity.add(polarity);
234     }
235
236     public Polarity getPolarity() {
237         return polarity;
238     }
239     
240     @Override
241     public void collectConcreteEffects(ArrayList<TCon> concreteEffects) {
242         if(ref != null)
243             ref.collectConcreteEffects(concreteEffects);
244     }
245
246     @Override
247     public Type head() {
248         if(ref != null)
249             return ref.head();
250         else
251             return this;
252     }
253
254     @Override
255     public Type copySkeleton(THashMap<TMetaVar, TMetaVar> metaVarMap) {
256         if(ref != null)
257             return ref.copySkeleton(metaVarMap);
258         else {
259             TMetaVar result = metaVarMap.get(this);
260             if(result == null) {
261                 result = new TMetaVar(kind, polarity);
262                 metaVarMap.put(this, result);
263             }
264             return result;
265         }
266     }
267
268     public void setSkeletonRef(Type type) throws UnificationException {
269         if(DEBUG)
270             System.out.println("setSkeletonRef " +  System.identityHashCode(this) + " -> " + type);
271         if(ref != null || skeletonRef != null)
272             throw new InternalCompilerError("Method setRef should be called only for unbound meta variables.");
273         if(type.contains(this))
274             throw new UnificationException(this, type);
275         this.skeletonRef = type;
276         fireNotifyAboutChange();
277     }
278     
279     @Override
280     public int hashCode() {
281         if(ref == null)
282             return System.identityHashCode(this);
283         else
284             return ref.hashCode();
285     }
286     
287     @Override
288     public int hashCode(int hash) {
289         if(ref == null)
290             return HashCodeUtils.update(hash, System.identityHashCode(this));
291         else
292             return ref.hashCode(hash);
293     }
294     
295     @Override
296     public int hashCode(int hash, TVar[] boundVars) {
297         if(ref == null)
298             return HashCodeUtils.update(hash, System.identityHashCode(this));
299         else
300             return ref.hashCode(hash, boundVars);
301     }
302     
303     @Override
304     public int skeletonHashCode() {
305         if(ref != null)
306             return ref.skeletonHashCode();
307         else if(skeletonRef != null)
308             return skeletonRef.skeletonHashCode();
309         else
310             return System.identityHashCode(this);
311     }
312     
313     @Override
314     public int skeletonHashCode(int hash) {
315         if(ref != null)
316             return ref.skeletonHashCode(hash);
317         else if(skeletonRef != null)
318             return skeletonRef.skeletonHashCode(hash);
319         else
320             return HashCodeUtils.update(hash, System.identityHashCode(this));
321     }
322     
323     @Override
324     public int skeletonHashCode(int hash, TVar[] boundVars) {
325         if(ref != null)
326             return ref.skeletonHashCode(hash, boundVars);
327         else if(skeletonRef != null)
328             return skeletonRef.skeletonHashCode(hash, boundVars);
329         else
330             return HashCodeUtils.update(hash, System.identityHashCode(this));
331     }
332     
333     @Override
334     public boolean equalsCanonical(Type other) {
335         return this == other;
336     }
337     
338     @Override
339     public Type canonical() {
340         if(ref == null)
341             return this;
342         else
343             return ref = ref.canonical();
344     }
345     
346     public void addListener(TMetaVarListener newListener) {
347         if(DEBUG)
348             System.out.println("addListener " + System.identityHashCode(this));
349         newListener.next = listener;
350         newListener.prev = this;
351         if(listener != null)
352             listener.prev = newListener;
353         listener = newListener;
354     }
355     
356     private void fireNotifyAboutChange() {
357         if(DEBUG)
358             System.out.println("fireNotifyAboutChange " + System.identityHashCode(this) + " " + ref);
359         TMetaVarListener cur = listener;
360         listener = null;
361         while(cur != null) {
362             if(DEBUG)
363                 System.out.println("    call listener");
364             cur.prev = null; // This prevents TMetaVarListener.remove from doing anything
365             cur.notifyAboutChange();
366             TMetaVarListener next = cur.next;
367             cur.next = null;
368             cur = next;
369         }
370     }
371     
372     public TMetaVarListener getLatestListener() {
373         return listener;
374     }
375
376     @Override
377     public Kind getKind(Environment context) {
378         return kind;
379     }
380
381     @Override
382     public Type[] skeletonCanonicalChildren() {
383         // Assumes that this is already canonical skeleton
384         return EMPTY_ARRAY;
385     }
386 }