1 package org.simantics.scl.compiler.types;
3 import java.util.ArrayList;
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;
19 import gnu.trove.map.hash.THashMap;
20 import gnu.trove.set.hash.THashSet;
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.
29 * @author Hannu Niemistö
31 public class TMetaVar extends Type {
32 public static final TMetaVar[] EMPTY_ARRAY = new TMetaVar[0];
33 public static final boolean DEBUG = false;
36 Type skeletonRef = null;
37 Polarity polarity = Polarity.NO_POLARITY;
39 private TMetaVarListener listener;
41 public static abstract class TMetaVarListener {
42 private Object prev; // TMetaVarListener or TMetaVar
43 private TMetaVarListener next;
45 public abstract void notifyAboutChange();
47 public void remove() {
49 return; // Not added or not anymore listening TMetaVar
50 if(prev instanceof TMetaVar)
51 ((TMetaVar)prev).listener = next;
53 ((TMetaVarListener)prev).next = next;
66 TMetaVar(Kind kind, Polarity polarity) {
68 this.polarity = polarity;
71 public Kind getKind() {
72 if(kind instanceof KMetaVar)
73 kind = Kinds.canonical(kind);
78 public Type replace(TVar var, Type replacement) {
82 Type newRef = ref.replace(var, replacement);
86 // We could also return newRef here, but in this way
87 // we don't have to copy so many parent types.
93 public TypeAst toTypeAst(TypeUnparsingContext context) {
95 return new TVarAst(/*polarity.getSymbol() +*/ context.getName(this));
97 return ref.toTypeAst(context);
101 public void updateHashCode(TypeHashCodeContext context) {
103 context.append(System.identityHashCode(this));
105 ref.updateHashCode(context);
109 public void collectFreeVars(ArrayList<TVar> vars) {
111 ref.collectFreeVars(vars);
115 public void collectMetaVars(ArrayList<TMetaVar> vars) {
119 ref.collectMetaVars(vars);
123 public void collectMetaVars(THashSet<TMetaVar> vars) {
127 ref.collectMetaVars(vars);
131 public void collectEffectMetaVars(ArrayList<TMetaVar> vars) {
133 ref.collectEffectMetaVars(vars);
136 public void setRef(Type type) throws UnificationException {
137 if(type instanceof TMetaVar && ((TMetaVar)type).ref != null)
138 throw new InternalCompilerError("Not canonical!");
140 throw new InternalCompilerError("Illegal setRef");
142 System.out.println("setRef " + System.identityHashCode(this) + " -> " + type);
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);
148 if(polarity != Polarity.NO_POLARITY)
149 type.addPolarity(polarity);
150 if(skeletonRef != null) {
151 Type skeleton = skeletonRef;
153 Skeletons.unifySkeletons(skeleton, type);
155 fireNotifyAboutChange();
158 public Type getRef() {
163 public boolean contains(TMetaVar other) {
165 return ref.contains(other);
166 else if(skeletonRef != null)
167 return skeletonRef.contains(other);
169 return this == other;
173 public Type convertMetaVarsToVars() {
175 if(kind == Kinds.EFFECT && !polarity.isNegative())
176 ref = Types.NO_EFFECTS;
178 ref = Types.var(getKind());
182 return ref.convertMetaVarsToVars();
186 public boolean isGround() {
190 return ref.isGround();
193 public Kind inferKind(Environment context) throws KindUnificationException {
194 return Kinds.metaVar();
198 public boolean containsMetaVars() {
202 return ref.containsMetaVars();
206 public void toName(TypeUnparsingContext context, StringBuilder b) {
208 ref.toName(context, b);
210 b.append(context.getName(this));
214 public int getClassId() {
219 public boolean isMaximal() {
220 return ref != null && ref.isMaximal();
224 public boolean isMinimal() {
225 return ref != null && ref.isMinimal();
229 public void addPolarity(Polarity polarity) {
231 ref.addPolarity(polarity);
233 this.polarity = this.polarity.add(polarity);
236 public Polarity getPolarity() {
241 public void collectConcreteEffects(ArrayList<TCon> concreteEffects) {
243 ref.collectConcreteEffects(concreteEffects);
255 public Type copySkeleton(THashMap<TMetaVar, TMetaVar> metaVarMap) {
257 return ref.copySkeleton(metaVarMap);
259 TMetaVar result = metaVarMap.get(this);
261 result = new TMetaVar(kind, polarity);
262 metaVarMap.put(this, result);
268 public void setSkeletonRef(Type type) throws UnificationException {
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();
280 public int hashCode() {
282 return System.identityHashCode(this);
284 return ref.hashCode();
288 public int hashCode(int hash) {
290 return HashCodeUtils.update(hash, System.identityHashCode(this));
292 return ref.hashCode(hash);
296 public int hashCode(int hash, TVar[] boundVars) {
298 return HashCodeUtils.update(hash, System.identityHashCode(this));
300 return ref.hashCode(hash, boundVars);
304 public int skeletonHashCode() {
306 return ref.skeletonHashCode();
307 else if(skeletonRef != null)
308 return skeletonRef.skeletonHashCode();
310 return System.identityHashCode(this);
314 public int skeletonHashCode(int hash) {
316 return ref.skeletonHashCode(hash);
317 else if(skeletonRef != null)
318 return skeletonRef.skeletonHashCode(hash);
320 return HashCodeUtils.update(hash, System.identityHashCode(this));
324 public int skeletonHashCode(int hash, TVar[] boundVars) {
326 return ref.skeletonHashCode(hash, boundVars);
327 else if(skeletonRef != null)
328 return skeletonRef.skeletonHashCode(hash, boundVars);
330 return HashCodeUtils.update(hash, System.identityHashCode(this));
334 public boolean equalsCanonical(Type other) {
335 return this == other;
339 public Type canonical() {
343 return ref = ref.canonical();
346 public void addListener(TMetaVarListener newListener) {
348 System.out.println("addListener " + System.identityHashCode(this));
349 newListener.next = listener;
350 newListener.prev = this;
352 listener.prev = newListener;
353 listener = newListener;
356 private void fireNotifyAboutChange() {
358 System.out.println("fireNotifyAboutChange " + System.identityHashCode(this) + " " + ref);
359 TMetaVarListener cur = listener;
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;
372 public TMetaVarListener getLatestListener() {
377 public Kind getKind(Environment context) {
382 public Type[] skeletonCanonicalChildren() {
383 // Assumes that this is already canonical skeleton