import org.simantics.scl.compiler.internal.elaboration.constraints.ReducedConstraints;
import org.simantics.scl.compiler.internal.elaboration.subsumption.SubSolver;
import org.simantics.scl.compiler.internal.elaboration.subsumption.Subsumption;
+import org.simantics.scl.compiler.types.Skeletons;
import org.simantics.scl.compiler.types.TApply;
import org.simantics.scl.compiler.types.TCon;
import org.simantics.scl.compiler.types.TForAll;
if(a instanceof TMetaVar) {
TMetaVar aVar = (TMetaVar)a;
- if(b instanceof TMetaVar)
+ if(b instanceof TMetaVar) {
+ Skeletons.unifySkeletons(a, b);
subsumptions.add(new Subsumption(loc, a, b));
+ }
else {
if(b.contains(aVar))
throw new UnificationException(a, b);
else if(type instanceof TMetaVar) {
TMetaVar var = (TMetaVar)type;
TMetaVar newVar = Types.metaVar(var.getKind());
+ try {
+ newVar.setSkeletonRef(var);
+ } catch (UnificationException e) {
+ throw new InternalCompilerError(loc, e);
+ }
subsumptions.add(new Subsumption(loc, newVar, var));
return newVar;
}
else if(type instanceof TMetaVar) {
TMetaVar var = (TMetaVar)type;
TMetaVar newVar = Types.metaVar(var.getKind());
+ try {
+ newVar.setSkeletonRef(var);
+ } catch (UnificationException e) {
+ throw new InternalCompilerError(loc, e);
+ }
subsumptions.add(new Subsumption(loc, var, newVar));
return newVar;
}
Types.unify(sub.a, sub.b);
} catch (UnificationException e) {
// Should not happen. Both types should be metavars.
- throw new InternalCompilerError();
+ throw new InternalCompilerError(e);
}
subsumptions.clear();
return true;
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;
}
public void setRef(Type type) throws UnificationException {
- if(type instanceof TMetaVar && ((TMetaVar)type).ref != null)
- throw new InternalCompilerError("Not canonical!");
+ //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<TMetaVar> seenVars = new IdentityHashSet<TMetaVar>();
+ refType(b, t, seenVars);
+ return b.toString();
+ }
+
+ private void refStructure(StringBuilder b, IdentityHashSet<TMetaVar> 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<TMetaVar> 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<TMetaVar> seenVars = new IdentityHashSet<TMetaVar>();
+ 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;
}
if(type.contains(this))
throw new UnificationException(this, type);
this.skeletonRef = type;
+ //checkRefLoop(this);
fireNotifyAboutChange();
}