private SemanticType propagate( Expr.IndexOf e, HashMap<String, SemanticType> environment, HashSet<String> generics, WyalFile.Context context) { SemanticType src_type = propagate(e.operand, environment, generics, context); SemanticType index_type = propagate(e.index, environment, generics, context); if (src_type instanceof SemanticType.EffectiveTuple) { SemanticType.EffectiveTuple tt = (SemanticType.EffectiveTuple) src_type; checkIsSubtype(SemanticType.Int, index_type, e.operand); if (!(e.index instanceof Expr.Constant)) { syntaxError("constant index required for tuple load", filename, e.index); } } else { checkIsSubtype(SemanticType.SetTupleAnyAny, src_type, e.operand); // FIXME: handle case for effective set (i.e. union of sets) SemanticType.Set st = (SemanticType.Set) src_type; SemanticType.EffectiveTuple tt = (SemanticType.EffectiveTuple) st.element(); // FIXME: handle case for effective tuple of wrong size checkIsSubtype(tt.tupleElement(0), index_type, e.index); } return src_type; }
/** * Calculate the most precise type that captures those possible values a given expression can * evaluate to. * * @param e * @return */ public static SemanticType returnType(Expr e) { SemanticType type = e.attribute(TypeAttribute.class).type; if (e instanceof Expr.Variable || e instanceof Expr.Constant || e instanceof Expr.Quantifier) { return type; } else if (e instanceof Expr.Unary) { Expr.Unary ue = (Expr.Unary) e; switch (ue.op) { case NOT: return SemanticType.Bool; case NEG: return type; case LENGTHOF: return SemanticType.Int; } } else if (e instanceof Expr.Binary) { Expr.Binary ue = (Expr.Binary) e; switch (ue.op) { case ADD: case SUB: case MUL: case DIV: case REM: case SETUNION: case SETINTERSECTION: case LISTAPPEND: case RANGE: return type; case EQ: case NEQ: case IMPLIES: case IFF: case LT: case LTEQ: case GT: case GTEQ: case IN: case SUBSET: case SUBSETEQ: case SUPSET: case SUPSETEQ: return SemanticType.Bool; } } else if (e instanceof Expr.Ternary) { Expr.Ternary ue = (Expr.Ternary) e; switch (ue.op) { case UPDATE: case SUBLIST: return type; } } else if (e instanceof Expr.Nary) { Expr.Nary ue = (Expr.Nary) e; switch (ue.op) { case AND: case OR: return SemanticType.Bool; case TUPLE: case SET: case LIST: return type; } } else if (e instanceof Expr.IndexOf) { Expr.IndexOf ue = (Expr.IndexOf) e; if (type instanceof SemanticType.EffectiveTuple) { SemanticType.EffectiveTuple tt = (SemanticType.EffectiveTuple) type; Value.Integer idx = (Value.Integer) ((Expr.Constant) ue.index).value; return tt.tupleElement(idx.value.intValue()); } else { SemanticType.Set st = (SemanticType.Set) type; SemanticType.EffectiveTuple tt = (SemanticType.EffectiveTuple) st.element(); return tt.tupleElement(1); } } else { Expr.FunCall fc = (Expr.FunCall) e; return ((SemanticType.Function) type).to(); } // should be deadcode. throw new IllegalArgumentException("Invalid opcode for expression"); }