]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
index 8d2307b232423d33182cfb8a130bc912af52012a..d78d745eb670c0ccb99719c2690e314e6a610488 100644 (file)
@@ -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;
+    }
 }