package org.simantics.scl.compiler.types;
-import gnu.trove.map.hash.THashMap;
-import gnu.trove.set.hash.THashSet;
-
import java.util.ArrayList;
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.internal.types.HashCodeUtils;
import org.simantics.scl.compiler.internal.types.TypeHashCodeContext;
import org.simantics.scl.compiler.internal.types.ast.TVarAst;
import org.simantics.scl.compiler.internal.types.ast.TypeAst;
import org.simantics.scl.compiler.types.util.Polarity;
import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.set.hash.THashSet;
+
/**
*/
public class TMetaVar extends Type {
public static final TMetaVar[] EMPTY_ARRAY = new TMetaVar[0];
+ public static final boolean DEBUG = false;
Type ref = null;
+ Type skeletonRef = null;
Polarity polarity = Polarity.NO_POLARITY;
private Kind kind;
+ private TMetaVarListener listener;
+
+ public static abstract class TMetaVarListener {
+ private Object prev; // TMetaVarListener or TMetaVar
+ private TMetaVarListener next;
+
+ public abstract void notifyAboutChange();
+
+ public void remove() {
+ if(prev == null)
+ return; // Not added or not anymore listening TMetaVar
+ if(prev instanceof TMetaVar)
+ ((TMetaVar)prev).listener = next;
+ else
+ ((TMetaVarListener)prev).next = next;
+ if(next != null) {
+ next.prev = prev;
+ next = null;
+ }
+ prev = null;
+ }
+ }
TMetaVar(Kind kind) {
this.kind = kind;
return ref.toTypeAst(context);
}
- @Override
- public int hashCode() {
- if(ref == null)
- return System.identityHashCode(this);
- else
- return ref.hashCode();
- }
-
@Override
public void updateHashCode(TypeHashCodeContext context) {
if(ref == null)
ref.collectEffectMetaVars(vars);
}
- public void setRef(Type a) throws UnificationException {
- a = Types.weakCanonical(a);
- if(a.contains(this))
- throw new UnificationException(this, a);
- ref = a;
+ public void setRef(Type type) throws UnificationException {
+ if(type instanceof TMetaVar && ((TMetaVar)type).ref != null)
+ throw new InternalCompilerError("Not canonical!");
+ if(type == this)
+ throw new InternalCompilerError("Illegal setRef");
+ if(DEBUG)
+ System.out.println("setRef " + System.identityHashCode(this) + " -> " + type);
+ if(ref != null)
+ throw new InternalCompilerError("Method setRef should be called only for unbound meta variables.");
+ if(type.contains(this))
+ throw new UnificationException(this, type);
+ ref = type;
if(polarity != Polarity.NO_POLARITY)
- a.addPolarity(polarity);
+ type.addPolarity(polarity);
+ if(skeletonRef != null) {
+ Type skeleton = skeletonRef;
+ skeletonRef = null;
+ Skeletons.unifySkeletons(skeleton, type);
+ }
+ fireNotifyAboutChange();
}
public Type getRef() {
@Override
public boolean contains(TMetaVar other) {
- if(ref == null)
- return this == other;
- else
+ if(ref != null)
return ref.contains(other);
+ else if(skeletonRef != null)
+ return skeletonRef.contains(other);
+ else
+ return this == other;
}
@Override
return result;
}
}
+
+ public void setSkeletonRef(Type type) throws UnificationException {
+ if(DEBUG)
+ System.out.println("setSkeletonRef " + System.identityHashCode(this) + " -> " + type);
+ if(ref != null || skeletonRef != null)
+ throw new InternalCompilerError("Method setRef should be called only for unbound meta variables.");
+ if(type.contains(this))
+ throw new UnificationException(this, type);
+ this.skeletonRef = type;
+ fireNotifyAboutChange();
+ }
+
+ @Override
+ public int hashCode() {
+ if(ref == null)
+ return System.identityHashCode(this);
+ else
+ return ref.hashCode();
+ }
+
+ @Override
+ public int hashCode(int hash) {
+ if(ref == null)
+ return HashCodeUtils.update(hash, System.identityHashCode(this));
+ else
+ return ref.hashCode(hash);
+ }
+
+ @Override
+ public int hashCode(int hash, TVar[] boundVars) {
+ if(ref == null)
+ return HashCodeUtils.update(hash, System.identityHashCode(this));
+ else
+ return ref.hashCode(hash, boundVars);
+ }
+
+ @Override
+ public int skeletonHashCode() {
+ if(ref != null)
+ return ref.skeletonHashCode();
+ else if(skeletonRef != null)
+ return skeletonRef.skeletonHashCode();
+ else
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public int skeletonHashCode(int hash) {
+ if(ref != null)
+ return ref.skeletonHashCode(hash);
+ else if(skeletonRef != null)
+ return skeletonRef.skeletonHashCode(hash);
+ else
+ return HashCodeUtils.update(hash, System.identityHashCode(this));
+ }
+
+ @Override
+ public int skeletonHashCode(int hash, TVar[] boundVars) {
+ if(ref != null)
+ return ref.skeletonHashCode(hash, boundVars);
+ else if(skeletonRef != null)
+ return skeletonRef.skeletonHashCode(hash, boundVars);
+ else
+ return HashCodeUtils.update(hash, System.identityHashCode(this));
+ }
+
+ @Override
+ public boolean equalsCanonical(Type other) {
+ return this == other;
+ }
+
+ @Override
+ public Type canonical() {
+ if(ref == null)
+ return this;
+ else
+ return ref = ref.canonical();
+ }
+
+ public void addListener(TMetaVarListener newListener) {
+ if(DEBUG)
+ System.out.println("addListener " + System.identityHashCode(this));
+ newListener.next = listener;
+ newListener.prev = this;
+ if(listener != null)
+ listener.prev = newListener;
+ listener = newListener;
+ }
+
+ private void fireNotifyAboutChange() {
+ if(DEBUG)
+ System.out.println("fireNotifyAboutChange " + System.identityHashCode(this) + " " + ref);
+ TMetaVarListener cur = listener;
+ listener = null;
+ while(cur != null) {
+ if(DEBUG)
+ System.out.println(" call listener");
+ cur.prev = null; // This prevents TMetaVarListener.remove from doing anything
+ cur.notifyAboutChange();
+ TMetaVarListener next = cur.next;
+ cur.next = null;
+ cur = next;
+ }
+ }
+
+ public TMetaVarListener getLatestListener() {
+ return listener;
+ }
+
+ @Override
+ public Kind getKind(Environment context) {
+ return kind;
+ }
+
+ @Override
+ public Type[] skeletonCanonicalChildren() {
+ // Assumes that this is already canonical skeleton
+ return EMPTY_ARRAY;
+ }
}