X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Ftypes%2FTMetaVar.java;h=00b289f46a1f1b934c5ab271386fedde11f38554;hb=624ab61bd302e999952f792e619a691e027ff1d2;hp=0d3114fc5765b0bad9a3ad11df5aaef8dc803bf1;hpb=eecd74faded034bd067094b42bbac0d286d8d9fa;p=simantics%2Fplatform.git 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 0d3114fc5..00b289f46 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 @@ -2,6 +2,7 @@ package org.simantics.scl.compiler.types; import java.util.ArrayList; +import org.simantics.databoard.util.IdentityHashSet; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.environment.Environment; import org.simantics.scl.compiler.internal.types.HashCodeUtils; @@ -97,14 +98,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) @@ -142,23 +135,112 @@ public class TMetaVar extends Type { } public void setRef(Type type) throws UnificationException { + //System.out.println("----"); + //System.out.println("this = " + refStructure(this)); + //System.out.println("type = " + refStructure(type)); + 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)) + Type thisSkeleton = Skeletons.canonicalSkeleton(this); + + if(type instanceof TMetaVar) { + TMetaVar other = (TMetaVar)type; + if(other.ref != null) + throw new InternalCompilerError("Not canonical!"); + + Type typeSkeleton = Skeletons.canonicalSkeleton(type); + if(thisSkeleton == typeSkeleton) { + if(skeletonRef != null) + setRefBase(type); + else + other.setRefBase(this); + return; + } + else if(thisSkeleton instanceof TMetaVar && type.contains((TMetaVar)thisSkeleton)) + throw new UnificationException(this, type); + } + else if(thisSkeleton instanceof TMetaVar && type.contains((TMetaVar)thisSkeleton)) throw new UnificationException(this, type); + + // Common case + if(skeletonRef != null) { + Skeletons.unifySkeletons(thisSkeleton, type); + } + setRefBase(type); + } + + private void setRefBase(Type type) throws UnificationException { + skeletonRef = null; ref = type; if(polarity != Polarity.NO_POLARITY) type.addPolarity(polarity); - if(skeletonRef != null) { - Type skeleton = skeletonRef; - skeletonRef = null; - Skeletons.unifySkeletons(skeleton, type); - } + //System.out.println("result = " + refStructure(this)); + //checkRefLoop(this); fireNotifyAboutChange(); } + private static String refStructure(Type t) { + StringBuilder b = new StringBuilder(); + IdentityHashSet seenVars = new IdentityHashSet(); + refType(b, t, seenVars); + return b.toString(); + } + + private void refStructure(StringBuilder b, IdentityHashSet seenVars) { + b.append(System.identityHashCode(this)); + if(!seenVars.add(this)) + b.append(" (loop)"); + else if(ref != null) { + b.append(" => "); + refType(b, ref, seenVars); + } + else if(skeletonRef != null) { + b.append(" -> "); + refType(b, skeletonRef, seenVars); + } + else + b.append(" (canonical)"); + } + + private static void refType(StringBuilder b, Type t, IdentityHashSet seenVars) { + if(t instanceof TMetaVar) + ((TMetaVar)t).refStructure(b, seenVars); + else { + b.append('['); + t.toString(new TypeUnparsingContext(), b); + b.append(']'); + } + } + + private void checkRefLoop(TMetaVar var) { + IdentityHashSet seenVars = new IdentityHashSet(); + StringBuilder b = new StringBuilder(); + while(true) { + b.append(var); + if(!seenVars.add(var)) + throw new InternalCompilerError("Cyclic meta var references: " + b); + if(var.ref != null) { + b.append(" => "); + if(var.ref instanceof TMetaVar) + var = (TMetaVar)var.ref; + else + return; + } + else if(var.skeletonRef != null) { + b.append(" -> "); + if(var.skeletonRef instanceof TMetaVar) + var = (TMetaVar)var.skeletonRef; + else + return; + } + else + return; + } + } + public Type getRef() { return ref; } @@ -277,9 +359,18 @@ public class TMetaVar extends Type { if(type.contains(this)) throw new UnificationException(this, type); this.skeletonRef = type; + //checkRefLoop(this); 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) @@ -296,6 +387,36 @@ public class TMetaVar extends Type { 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; @@ -343,4 +464,10 @@ public class TMetaVar extends Type { public Kind getKind(Environment context) { return kind; } + + @Override + public Type[] skeletonCanonicalChildren() { + // Assumes that this is already canonical skeleton + return EMPTY_ARRAY; + } }