if (!(b1 instanceof PrimSig) || b1!=b2 || b1!=b3) break;
PrimSig sub = (PrimSig)b1;
Field f1 = s.getFields().get(0), f2 = s.getFields().get(1);
if (sub.isEnum==null || !list.args.get(0).isSame(sub) || !list.args.get(1).isSame(s.join(f1)) || !list.args.get(2).isSame(s.join(f2))) break;
// Now, we've confirmed it is a total ordering on an enum. Let's pre-bind the relations
TupleSet me = sol.query(true, sol.a2k(s), false), firstTS = factory.noneOf(2), lastTS = null, nextTS = factory.noneOf(3);
if (me.size()!=1 || me.arity()!=1) break;
int n = sub.children().size();
for(PrimSig c: sub.children()) {
TupleSet TS = sol.query(true, sol.a2k(c), false);
if (TS.size()!=1 || TS.arity()!=1) { firstTS=factory.noneOf(2); nextTS=factory.noneOf(3); break; }
if (lastTS==null) { firstTS=me.product(TS); lastTS=TS; continue; }
nextTS.addAll(me.product(lastTS).product(TS));
lastTS=TS;
}
if (firstTS.size()!=(n>0 ? 1 : 0) || nextTS.size() != n-1) break;
sol.addField(f1, sol.addRel(s.label+"."+f1.label, firstTS, firstTS));
sol.addField(f2, sol.addRel(s.label+"."+f2.label, nextTS, nextTS));
rep.bound("Field "+s.label+"."+f1.label+" == "+firstTS+"\n");
rep.bound("Field "+s.label+"."+f2.label+" == "+nextTS+"\n");
continue again;
}
for(Field f:s.getFields()) {
boolean isOne = s.isOne!=null;
if (isOne && f.decl().expr.mult()==ExprUnary.Op.EXACTLYOF) {
Expression sim = sim(f.decl().expr);
if (sim!=null) {
rep.bound("Field "+s.label+"."+f.label+" defined to be "+sim+"\n");
sol.addField(f, sol.a2k(s).product(sim));
continue;
}
}
Type t = isOne ? Sig.UNIV.type().join(f.type()) : f.type();
TupleSet ub = factory.noneOf(t.arity());
for(List<PrimSig> p:t.fold()) {
TupleSet upper=null;
for(PrimSig b:p) {
TupleSet tmp = sol.query(true, sol.a2k(b), false);
if (upper==null) upper=tmp; else upper=upper.product(tmp);
}
ub.addAll(upper);
}
Relation r = sol.addRel(s.label+"."+f.label, null, ub);
sol.addField(f, isOne ? sol.a2k(s).product(r) : r);
}
}
// Add any additional SIZE constraints
for(Sig s:sigs) if (!s.builtin) {
Expression exp = sol.a2k(s);
TupleSet upper = sol.query(true,exp,false), lower=sol.query(false,exp,false);
final int n = sc.sig2scope(s);
if (s.isOne!=null && (lower.size()!=1 || upper.size()!=1)) {
rep.bound("Sig "+s+" in "+upper+" with size==1\n");
sol.addFormula(exp.one(), s.isOne);
continue;
}
if (s.isSome!=null && lower.size()<1) sol.addFormula(exp.some(), s.isSome);
if (s.isLone!=null && upper.size()>1) sol.addFormula(exp.lone(), s.isLone);
if (n<0) continue; // This means no scope was specified
if (lower.size()==n && upper.size()==n && sc.isExact(s)) {
rep.bound("Sig "+s+" == "+upper+"\n");
}
else if (sc.isExact(s)) {
rep.bound("Sig "+s+" in "+upper+" with size=="+n+"\n");
sol.addFormula(size(s,n,true), Pos.UNKNOWN);
}
else if (upper.size()<=n){
rep.bound("Sig "+s+" in "+upper+"\n");
}
else {
rep.bound("Sig "+s+" in "+upper+" with size<="+n+"\n");
sol.addFormula(size(s,n,false), Pos.UNKNOWN);