Search in sources :

Example 1 with ErrorWarning

use of edu.mit.csail.sdg.alloy4.ErrorWarning in project org.alloytools.alloy by AlloyTools.

the class CompModule method resolveAll.

// ============================================================================================================================//
/**
 * This method resolves the entire world; NOTE: if it throws an exception, it
 * may leave the world in an inconsistent state!
 */
static CompModule resolveAll(final A4Reporter rep, final CompModule root) throws Err {
    final List<ErrorWarning> warns = new ArrayList<ErrorWarning>();
    for (CompModule m : root.getAllReachableModules()) root.allModules.add(m);
    resolveParams(rep, root.allModules);
    resolveModules(rep, root.allModules);
    for (CompModule m : root.allModules) for (Sig s : m.sigs.values()) root.sig2module.put(s, m);
    // Resolves SigAST -> Sig, and topologically sort the sigs into the
    // "sorted" array
    root.new2old.put(UNIV, UNIV);
    root.new2old.put(SIGINT, SIGINT);
    root.new2old.put(SEQIDX, SEQIDX);
    root.new2old.put(STRING, STRING);
    root.new2old.put(NONE, NONE);
    HashSet<Object> topo = new HashSet<Object>();
    for (CompModule m : root.allModules) for (Sig s : m.sigs.values()) resolveSig(root, topo, s);
    // (since fields in subsigs are allowed to refer to parent's fields)
    for (Sig oldS : root.new2old.keySet()) resolveFieldDecl(root, rep, oldS, warns, false);
    // Typecheck the function declarations
    JoinableList<Err> errors = new JoinableList<Err>();
    for (CompModule x : root.allModules) errors = x.resolveFuncDecls(rep, errors, warns);
    if (!errors.isEmpty())
        throw errors.pick();
    // Typecheck the defined fields
    for (Sig oldS : root.new2old.keySet()) resolveFieldDecl(root, rep, oldS, warns, true);
    if (Version.experimental && root.seenDollar)
        resolveMeta(root);
    // Reject name clash
    rejectNameClash(root.allModules);
    // to function declarations)
    for (CompModule x : root.allModules) {
        errors = x.resolveFuncBody(rep, errors, warns);
        errors = x.resolveAssertions(rep, errors, warns);
        errors = x.resolveFacts(root, rep, errors, warns);
        // root module's list of exact sigs
        for (String n : x.exactParams) {
            Sig sig = x.params.get(n);
            if (sig != null)
                root.exactSigs.add(sig);
        }
    }
    if (!errors.isEmpty())
        throw errors.pick();
    // Typecheck the run/check commands (which can refer to function bodies
    // and assertions)
    root.resolveCommands(root.getAllReachableFacts());
    if (!errors.isEmpty())
        throw errors.pick();
    for (ErrorWarning w : warns) rep.warning(w);
    for (Sig s : root.exactSigs) rep.debug("Forced to be exact: " + s + "\n");
    return root;
}
Also used : PrimSig(edu.mit.csail.sdg.ast.Sig.PrimSig) Sig(edu.mit.csail.sdg.ast.Sig) SubsetSig(edu.mit.csail.sdg.ast.Sig.SubsetSig) Err(edu.mit.csail.sdg.alloy4.Err) ArrayList(java.util.ArrayList) ErrorWarning(edu.mit.csail.sdg.alloy4.ErrorWarning) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) JoinableList(edu.mit.csail.sdg.alloy4.JoinableList)

Example 2 with ErrorWarning

use of edu.mit.csail.sdg.alloy4.ErrorWarning in project org.alloytools.alloy by AlloyTools.

the class CompModule method resolveFieldDecl.

// ============================================================================================================================//
private static void resolveFieldDecl(CompModule res, final A4Reporter rep, final Sig s, final List<ErrorWarning> warns, boolean defined) throws Err {
    // When typechecking each field:
    // * it is allowed to refer to earlier fields in the same SIG or in any
    // visible ancestor sig
    // * it is allowed to refer to visible sigs
    // * it is NOT allowed to refer to any predicate or function
    // For example, if A.als opens B.als, and B/SIGX extends A/SIGY,
    // then B/SIGX's fields cannot refer to A/SIGY, nor any fields in
    // A/SIGY)
    final List<Decl> oldDecls = res.old2fields.get(res.new2old.get(s));
    if (oldDecls == null)
        return;
    final CompModule m = res.sig2module.get(s);
    final Context cx = new Context(m, warns);
    final ExprHasName dup = Decl.findDuplicateName(oldDecls);
    if (dup != null)
        throw new ErrorSyntax(dup.span(), "sig \"" + s + "\" cannot have 2 fields named \"" + dup.label + "\"");
    for (final Decl d : oldDecls) {
        if (d.expr.mult() != ExprUnary.Op.EXACTLYOF) {
            if (defined)
                continue;
        } else {
            if (!defined)
                continue;
        }
        // The name "this" does matter, since the parser and the typechecker
        // both refer to it as "this"
        cx.rootfield = d;
        cx.rootsig = s;
        cx.put("this", s.decl.get());
        Expr bound = cx.check(d.expr).resolve_as_set(warns);
        cx.remove("this");
        String[] names = new String[d.names.size()];
        for (int i = 0; i < names.length; i++) names[i] = d.names.get(i).label;
        Field[] fields = s.addTrickyField(d.span(), d.isPrivate, d.disjoint, d.disjoint2, null, names, bound);
        for (Field f : fields) {
            rep.typecheck("Sig " + s + ", Field " + f.label + ": " + f.type() + "\n");
        }
    }
}
Also used : Field(edu.mit.csail.sdg.ast.Sig.Field) ErrorSyntax(edu.mit.csail.sdg.alloy4.ErrorSyntax) Expr(edu.mit.csail.sdg.ast.Expr) ExprHasName(edu.mit.csail.sdg.ast.ExprHasName) Decl(edu.mit.csail.sdg.ast.Decl)

Example 3 with ErrorWarning

use of edu.mit.csail.sdg.alloy4.ErrorWarning in project org.alloytools.alloy by AlloyTools.

the class CompModule method resolveFuncBody.

/**
 * Each Func's body will now be typechecked Expr object.
 */
private JoinableList<Err> resolveFuncBody(A4Reporter rep, JoinableList<Err> errors, List<ErrorWarning> warns) throws Err {
    for (ArrayList<Func> entry : funcs.values()) for (Func ff : entry) {
        Context cx = new Context(this, warns);
        cx.rootfunbody = ff;
        for (Decl d : ff.decls) for (ExprHasName n : d.names) cx.put(n.label, n);
        Expr newBody = cx.check(ff.getBody());
        if (ff.isPred)
            newBody = newBody.resolve_as_formula(warns);
        else
            newBody = newBody.resolve_as_set(warns);
        errors = errors.make(newBody.errors);
        if (!newBody.errors.isEmpty())
            continue;
        try {
            ff.setBody(newBody);
        } catch (Err er) {
            errors = errors.make(er);
            continue;
        }
        if (warns != null && ff.returnDecl.type().hasTuple() && newBody.type().hasTuple() && !newBody.type().intersects(ff.returnDecl.type()))
            warns.add(new ErrorWarning(newBody.span(), "Function return value is disjoint from its return type.\n" + "Function body has type " + newBody.type() + "\n" + "but the return type is " + ff.returnDecl.type()));
        // else if (warns!=null && Version.experimental &&
        // !newBody.type.isSubtypeOf(ff.returnDecl.type))
        // warns.add(new ErrorWarning(newBody.span(),
        // "Function may return a tuple not in its declared return
        // type.\n"
        // +"The Alloy Analyzer's analysis may be unsound\n"
        // +"if it returns a tuple outside its declared return type.\n"
        // +"Function body has type "+newBody.type+"\nbut the return
        // type is "+ff.returnDecl.type));
        rep.typecheck(ff.toString() + ", BODY:" + newBody.type() + "\n");
    }
    return errors;
}
Also used : Expr(edu.mit.csail.sdg.ast.Expr) Err(edu.mit.csail.sdg.alloy4.Err) Func(edu.mit.csail.sdg.ast.Func) ExprHasName(edu.mit.csail.sdg.ast.ExprHasName) ErrorWarning(edu.mit.csail.sdg.alloy4.ErrorWarning) Decl(edu.mit.csail.sdg.ast.Decl)

Example 4 with ErrorWarning

use of edu.mit.csail.sdg.alloy4.ErrorWarning in project org.alloytools.alloy by AlloyTools.

the class ExprBinary method resolve.

// ============================================================================================================//
/**
 * {@inheritDoc}
 */
@Override
public Expr resolve(Type p, Collection<ErrorWarning> warns) {
    if (errors.size() > 0)
        return this;
    ErrorWarning w = null;
    Type a = left.type, b = right.type;
    switch(op) {
        case MUL:
        case DIV:
        case REM:
        case LT:
        case LTE:
        case GT:
        case GTE:
        case SHL:
        case SHR:
        case SHA:
        case NOT_LTE:
        case NOT_GTE:
        case NOT_LT:
        case NOT_GT:
            {
                a = (b = Type.smallIntType());
                break;
            }
        case AND:
        case OR:
        case IFF:
        case IMPLIES:
            {
                a = (b = Type.FORMULA);
                break;
            }
        case EQUALS:
        case NOT_EQUALS:
            {
                p = a.intersect(b);
                if (p.hasTuple()) {
                    a = p;
                    b = p;
                } else {
                    a = a.pickCommonArity(b);
                    b = b.pickCommonArity(a);
                }
                // } else
                if (warns == null) {
                    break;
                } else if (left.type.hasTuple() && right.type.hasTuple() && !(left.type.intersects(right.type))) {
                    w = warn("== is redundant, because the left and right expressions are always disjoint.");
                } else if (left.isSame(right)) {
                    w = warn("== is redundant, because the left and right expressions always have the same value.");
                }
                break;
            }
        case IN:
        case NOT_IN:
            {
                a = a.pickCommonArity(b);
                b = b.intersect(a);
                if (warns == null)
                    break;
                if (left.type.hasNoTuple() && right.type.hasNoTuple())
                    w = warn("Subset operator is redundant, because both subexpressions are always empty.");
                else if (left.type.hasNoTuple())
                    w = warn("Subset operator is redundant, because the left subexpression is always empty.");
                else if (right.type.hasNoTuple())
                    w = warn("Subset operator is redundant, because the right subexpression is always empty.");
                else if (b.hasNoTuple())
                    w = warn("Subset operator is redundant, because the left and right subexpressions are always disjoint.");
                else if (left.isSame(right))
                    w = warn("Subset operator is redundant, because the left and right expressions always have the same value.");
                break;
            }
        case INTERSECT:
            {
                a = a.intersect(p);
                b = b.intersect(p);
                if (warns != null && type.hasNoTuple())
                    w = warn("& is irrelevant because the two subexpressions are always disjoint.");
                break;
            }
        case IPLUS:
        case IMINUS:
            {
                a = Type.smallIntType();
                b = Type.smallIntType();
                break;
            }
        case PLUSPLUS:
        case PLUS:
            {
                a = a.intersect(p);
                b = b.intersect(p);
                // b=Type.makeInt(b); }
                if (warns == null)
                    break;
                if (a == EMPTY && b == EMPTY)
                    w = warn(this + " is irrelevant since both subexpressions are redundant.", p);
                else if (a == EMPTY)
                    w = warn(this + " is irrelevant since the left subexpression is redundant.", p);
                else if (b == EMPTY || (op == Op.PLUSPLUS && !right.type.canOverride(left.type)))
                    w = warn(this + " is irrelevant since the right subexpression is redundant.", p);
                break;
            }
        case MINUS:
            {
                a = p;
                b = p.intersect(b);
                // } else
                if (warns != null && (type.hasNoTuple() || b.hasNoTuple())) {
                    w = warn("- is irrelevant since the right expression is redundant.", p);
                }
                break;
            }
        case JOIN:
            {
                if (warns != null && type.hasNoTuple())
                    w = warn("The join operation here always yields an empty set.");
                a = (b = EMPTY);
                for (ProductType aa : left.type) for (ProductType bb : right.type) if (p.hasArity(aa.arity() + bb.arity() - 2)) {
                    PrimSig j = aa.get(aa.arity() - 1).intersect(bb.get(0));
                    if (j != Sig.NONE)
                        for (ProductType cc : p.intersect(aa.join(bb))) if (!cc.isEmpty()) {
                            List<PrimSig> v = new ArrayList<PrimSig>(cc.arity() + 1);
                            for (int i = 0; i < cc.arity(); i++) v.add(cc.get(i));
                            v.add(aa.arity() - 1, j);
                            a = a.merge(Type.make(v, 0, aa.arity()));
                            b = b.merge(Type.make(v, aa.arity() - 1, v.size()));
                        }
                }
                if (a == EMPTY || b == EMPTY) {
                    // Continue the best we can; we
                    // should have issued a
                    // relevance warning elsewhere
                    // already.
                    a = (b = EMPTY);
                    for (ProductType aa : left.type) for (ProductType bb : right.type) if (p.hasArity(aa.arity() + bb.arity() - 2) && aa.get(aa.arity() - 1).intersects(bb.get(0))) {
                        a = a.merge(aa);
                        b = b.merge(bb);
                    }
                }
                if (a == EMPTY || b == EMPTY) {
                    // Continue the best we can; we
                    // should have issued a
                    // relevance warning elsewhere
                    // already.
                    a = (b = EMPTY);
                    for (ProductType aa : left.type) for (ProductType bb : right.type) if (p.hasArity(aa.arity() + bb.arity() - 2)) {
                        a = a.merge(aa);
                        b = b.merge(bb);
                    }
                }
                break;
            }
        case DOMAIN:
            {
                // leftType such that r1<:r2 in parentType}
                if (warns != null && type.hasNoTuple())
                    w = warn("<: is irrelevant because the result is always empty.");
                Type leftType = EMPTY, rightType = EMPTY;
                for (ProductType aa : a) if (aa.arity() == 1)
                    for (ProductType bb : b) if (p.hasArity(bb.arity()))
                        for (ProductType cc : p.intersect(bb.columnRestrict(aa.get(0), 0))) if (!cc.isEmpty()) {
                            leftType = leftType.merge(cc, 0, 1);
                            rightType = rightType.merge(cc);
                        }
                if (leftType == EMPTY || rightType == EMPTY) {
                    // We try to
                    // proceed the
                    // best we can
                    leftType = a.extract(1);
                    rightType = b.pickCommonArity(p);
                }
                a = leftType;
                b = rightType;
                break;
            }
        case RANGE:
            {
                // leftType such that r1:>r2 in parentType}
                if (warns != null && type.hasNoTuple())
                    w = warn(":> is irrelevant because the result is always empty.");
                Type leftType = EMPTY, rightType = EMPTY;
                for (ProductType bb : b) if (bb.arity() == 1)
                    for (ProductType aa : a) if (p.hasArity(aa.arity()))
                        for (ProductType cc : p.intersect(aa.columnRestrict(bb.get(0), aa.arity() - 1))) if (!cc.isEmpty()) {
                            leftType = leftType.merge(cc);
                            rightType = rightType.merge(cc, cc.arity() - 1, cc.arity());
                        }
                if (leftType == EMPTY || rightType == EMPTY) {
                    // We try to
                    // proceed the
                    // best we can
                    leftType = a.pickCommonArity(p);
                    rightType = b.extract(1);
                }
                a = leftType;
                b = rightType;
                break;
            }
        default:
            {
                // leftType such that r1->r2 in parentType}
                if (warns == null) {
                // do nothing
                } else if (a.hasTuple()) {
                    if (b.hasNoTuple())
                        w = warn("The left expression of -> is irrelevant because the right expression is always empty.");
                } else {
                    if (b.hasTuple())
                        w = warn("The right expression of -> is irrelevant because the left expression is always empty.");
                }
                Type leftType = EMPTY, rightType = EMPTY;
                for (ProductType aa : a) if (!aa.isEmpty())
                    for (ProductType bb : b) if (!bb.isEmpty() && p.hasArity(aa.arity() + bb.arity()))
                        for (ProductType cc : p.intersect(aa.product(bb))) if (!cc.isEmpty()) {
                            leftType = leftType.merge(cc, 0, aa.arity());
                            rightType = rightType.merge(cc, aa.arity(), cc.arity());
                        }
                // relevance warning already.
                if (leftType == EMPTY || rightType == EMPTY) {
                    leftType = a;
                    rightType = b;
                }
                a = leftType;
                b = rightType;
            }
    }
    Expr left = this.left.resolve(a, warns);
    Expr right = this.right.resolve(b, warns);
    if (w != null)
        warns.add(w);
    return (left == this.left && right == this.right) ? this : op.make(pos, closingBracket, left, right);
}
Also used : ErrorType(edu.mit.csail.sdg.alloy4.ErrorType) ProductType(edu.mit.csail.sdg.ast.Type.ProductType) ProductType(edu.mit.csail.sdg.ast.Type.ProductType) ErrorWarning(edu.mit.csail.sdg.alloy4.ErrorWarning) ArrayList(java.util.ArrayList) List(java.util.List) JoinableList(edu.mit.csail.sdg.alloy4.JoinableList) PrimSig(edu.mit.csail.sdg.ast.Sig.PrimSig)

Example 5 with ErrorWarning

use of edu.mit.csail.sdg.alloy4.ErrorWarning in project org.alloytools.alloy by AlloyTools.

the class ExprChoice method resolveHelper.

// ============================================================================================================//
/**
 * Resolve the list of choices, or return an ExprBad object containing the list
 * of unresolvable ambiguities.
 */
private Expr resolveHelper(boolean firstPass, final Type t, List<Expr> choices, List<String> reasons, Collection<ErrorWarning> warns) {
    List<Expr> ch = new ArrayList<Expr>(choices.size());
    List<String> re = new ArrayList<String>(choices.size());
    // We first prefer exact matches
    for (int i = 0; i < choices.size(); i++) {
        Type tt = choices.get(i).type;
        if (/* [AM](t.is_int() && tt.is_int()) || */
        (t.is_bool && tt.is_bool) || t.intersects(tt)) {
            ch.add(choices.get(i));
            re.add(reasons.get(i));
        }
    }
    // If none, we try any legal matches
    if (ch.size() == 0) {
        for (int i = 0; i < choices.size(); i++) if (choices.get(i).type.hasCommonArity(t)) {
            ch.add(choices.get(i));
            re.add(reasons.get(i));
        }
    }
    // If too many, then keep the choices with the smallest weight
    if (ch.size() > 1) {
        List<Expr> ch2 = new ArrayList<Expr>(ch.size());
        List<String> re2 = new ArrayList<String>(ch.size());
        long w = 0;
        for (int i = 0; i < ch.size(); i++) {
            Expr c = ch.get(i);
            String r = re.get(i);
            if (ch2.size() > 0 && c.weight > w)
                continue;
            else if (ch2.size() == 0 || c.weight < w) {
                ch2.clear();
                re2.clear();
                w = c.weight;
            }
            ch2.add(c);
            re2.add(r);
        }
        ch = ch2;
        re = re2;
        // resolve them all and try again
        if (firstPass && ch.size() > 1) {
            ch2 = new ArrayList<Expr>(ch.size());
            for (Expr c : ch) ch2.add(c.resolve(t, null));
            return resolveHelper(false, t, ch2, re, warns);
        }
    }
    // If we are down to exactly 1 match, return it
    if (ch.size() == 1)
        return ch.get(0).resolve(t, warns);
    // emptyset-of-the-same-arity, then just return emptyset
    none: while (ch.size() > 1) {
        int arity = -1;
        for (Expr c : ch) {
            if (c.type.is_bool || c.type.is_int() || c.type.hasTuple())
                break none;
            int a = c.type.arity();
            if (a < 1)
                break none;
            if (arity < 0)
                arity = a;
            else if (arity != a)
                break none;
        }
        Expr ans = Sig.NONE;
        while (arity > 1) {
            ans = ans.product(Sig.NONE);
            arity--;
        }
        return ExprUnary.Op.NOOP.make(span(), ans);
    }
    // Otherwise, complain!
    String txt;
    if (ch.size() > 1) {
        txt = "\nThis name is ambiguous due to multiple matches:";
    } else {
        txt = "\nThis name cannot be resolved; its relevant type does not intersect with any of the following candidates:";
        re = reasons;
    }
    StringBuilder msg = new StringBuilder(txt);
    for (String r : re) msg.append('\n').append(r);
    return new ExprBad(pos, toString(), new ErrorType(pos, msg.toString()));
}
Also used : ErrorType(edu.mit.csail.sdg.alloy4.ErrorType) ErrorType(edu.mit.csail.sdg.alloy4.ErrorType) ArrayList(java.util.ArrayList)

Aggregations

ErrorType (edu.mit.csail.sdg.alloy4.ErrorType)8 ErrorWarning (edu.mit.csail.sdg.alloy4.ErrorWarning)7 Expr (edu.mit.csail.sdg.ast.Expr)5 Decl (edu.mit.csail.sdg.ast.Decl)4 ExprHasName (edu.mit.csail.sdg.ast.ExprHasName)4 TempList (edu.mit.csail.sdg.alloy4.ConstList.TempList)3 Err (edu.mit.csail.sdg.alloy4.Err)3 Func (edu.mit.csail.sdg.ast.Func)3 ArrayList (java.util.ArrayList)3 JoinableList (edu.mit.csail.sdg.alloy4.JoinableList)2 Command (edu.mit.csail.sdg.ast.Command)2 Module (edu.mit.csail.sdg.ast.Module)2 Sig (edu.mit.csail.sdg.ast.Sig)2 PrimSig (edu.mit.csail.sdg.ast.Sig.PrimSig)2 ProductType (edu.mit.csail.sdg.ast.Type.ProductType)2 A4Options (edu.mit.csail.sdg.translator.A4Options)2 A4Solution (edu.mit.csail.sdg.translator.A4Solution)2 A4Reporter (edu.mit.csail.sdg.alloy4.A4Reporter)1 ErrorSyntax (edu.mit.csail.sdg.alloy4.ErrorSyntax)1 Pos (edu.mit.csail.sdg.alloy4.Pos)1