/** * Perform type propagation through a given expression, returning the type of value that is * returned by evaluating this expression. * * @param e * @param environment * @param generics * @param context * @return */ private SemanticType propagate( Expr e, HashMap<String, SemanticType> environment, HashSet<String> generics, WyalFile.Context context) { SemanticType t; if (e instanceof Expr.Variable) { t = propagate((Expr.Variable) e, environment, generics, context); } else if (e instanceof Expr.Constant) { t = propagate((Expr.Constant) e, environment, generics, context); } else if (e instanceof Expr.Unary) { t = propagate((Expr.Unary) e, environment, generics, context); } else if (e instanceof Expr.Binary) { t = propagate((Expr.Binary) e, environment, generics, context); } else if (e instanceof Expr.Ternary) { t = propagate((Expr.Ternary) e, environment, generics, context); } else if (e instanceof Expr.Nary) { t = propagate((Expr.Nary) e, environment, generics, context); } else if (e instanceof Expr.Quantifier) { t = propagate((Expr.Quantifier) e, environment, generics, context); } else if (e instanceof Expr.FunCall) { t = propagate((Expr.FunCall) e, environment, generics, context); } else if (e instanceof Expr.IndexOf) { t = propagate((Expr.IndexOf) e, environment, generics, context); } else { internalFailure("unknown expression encountered (" + e + ")", filename, e); return null; } e.attributes().add(new TypeAttribute(t)); return returnType(e); }
/** * 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"); }