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=1596467bc2931541350fdfd0fd27a424e084e882;hb=e515d1fda563f0fa3b8b71f9099696cf49a06d25;hp=0d3114fc5765b0bad9a3ad11df5aaef8dc803bf1;hpb=3303fe4a3b363e88662ac75a4f7e873ddb3ab352;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..1596467bc 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; @@ -91,18 +92,12 @@ public class TMetaVar extends Type { @Override public TypeAst toTypeAst(TypeUnparsingContext context) { - if(ref == null) - return new TVarAst(/*polarity.getSymbol() +*/ context.getName(this)); - else + if(ref != null) return ref.toTypeAst(context); - } - - @Override - public int hashCode() { - if(ref == null) - return System.identityHashCode(this); + else if(context.showSkeletons && skeletonRef != null) + return skeletonRef.toTypeAst(context); else - return ref.hashCode(); + return new TVarAst(/*polarity.getSymbol() +*/ context.getName(this)); } @Override @@ -142,23 +137,116 @@ 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); + if(ref != null) { + Types.unify(this, type); + return; + } + } + 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 +365,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 +393,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 +470,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; + } }