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=d78d745eb670c0ccb99719c2690e314e6a610488;hp=8d2307b232423d33182cfb8a130bc912af52012a;hb=1b4d8b692f40d946deb5db8280eb4ca5b36a75a7;hpb=969bd23cab98a79ca9101af33334000879fb60c5 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..d78d745eb 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; @@ -71,14 +97,6 @@ public class TMetaVar extends Type { 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) @@ -115,13 +133,26 @@ 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(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() { @@ -130,10 +161,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 +264,123 @@ 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() { + 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; + } }