X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Ftypes%2FTMetaVar.java;h=0d3114fc5765b0bad9a3ad11df5aaef8dc803bf1;hp=8d2307b232423d33182cfb8a130bc912af52012a;hb=9a175feb652b2b7bba7afa540831b9076be3c10e;hpb=0b72d3e4ec886838314ffeba0fa201e32c0aae3e diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/types/TMetaVar.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/types/TMetaVar.java index 8d2307b23..0d3114fc5 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/types/TMetaVar.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/types/TMetaVar.java @@ -1,11 +1,10 @@ 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; @@ -17,6 +16,9 @@ import org.simantics.scl.compiler.types.kinds.Kinds; 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; + /** @@ -28,10 +30,34 @@ import org.simantics.scl.compiler.types.util.TypeUnparsingContext; */ 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; @@ -115,13 +141,22 @@ public class TMetaVar extends Type { 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(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() { @@ -130,10 +165,12 @@ public class TMetaVar extends Type { @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 @@ -231,4 +268,79 @@ public class TMetaVar extends Type { 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(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 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; + } }