private void propagate( TypePattern pattern, HashMap<String, SemanticType> environment, HashSet<String> generics, WyalFile.Context context) { SemanticType type = builder.convert(pattern.toSyntacticType(), generics, context); if (pattern instanceof TypePattern.Tuple) { TypePattern.Tuple tt = (TypePattern.Tuple) pattern; for (TypePattern p : tt.patterns) { propagate(p, environment, generics, context); } } if (pattern.var != null) { environment.put(pattern.var, type); } if (pattern.source != null) { SemanticType ct = propagate(pattern.source, environment, generics, context); checkIsSubtype(SemanticType.SetAny, ct, pattern); // TODO: need effective set here SemanticType.Set set_t = (SemanticType.Set) ct; checkIsSubtype(type, set_t.element(), pattern); } if (pattern.constraint != null) { SemanticType ct = propagate(pattern.constraint, environment, generics, context); checkIsSubtype(SemanticType.Bool, ct, pattern); } pattern.attributes().add(new TypeAttribute(type)); }
private SemanticType propagate( Expr.Ternary e, HashMap<String, SemanticType> environment, HashSet<String> generics, WyalFile.Context context) { SemanticType firstType = propagate(e.firstOperand, environment, generics, context); SemanticType secondType = propagate(e.secondOperand, environment, generics, context); SemanticType thirdType = propagate(e.thirdOperand, environment, generics, context); switch (e.op) { case UPDATE: checkIsSubtype(SemanticType.SetTupleAnyAny, firstType, e.firstOperand); // FIXME: should this handle map updates? checkIsSubtype(SemanticType.Int, secondType, e.secondOperand); SemanticType.Set l = (SemanticType.Set) firstType; SemanticType.Tuple elementType = SemanticType.Tuple(SemanticType.Int, thirdType); checkIsSubtype(l.element(), elementType, e.thirdOperand); return firstType; case SUBLIST: checkIsSubtype(SemanticType.SetTupleAnyAny, firstType, e.firstOperand); checkIsSubtype(SemanticType.Int, secondType, e.secondOperand); checkIsSubtype(SemanticType.Int, thirdType, e.thirdOperand); return firstType; } internalFailure("unknown ternary expression encountered (" + e + ")", filename, e); return null; // deadcode }
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"); }
private SemanticType propagate( Expr.Binary e, HashMap<String, SemanticType> environment, HashSet<String> generics, WyalFile.Context context) { SemanticType lhs_type = propagate(e.leftOperand, environment, generics, context); SemanticType rhs_type = propagate(e.rightOperand, environment, generics, context); switch (e.op) { case ADD: case SUB: case MUL: case DIV: case REM: checkIsSubtype(SemanticType.IntOrReal, lhs_type, e.leftOperand); checkIsSubtype(SemanticType.IntOrReal, rhs_type, e.rightOperand); return SemanticType.Or(lhs_type, rhs_type); case EQ: case NEQ: return SemanticType.Or(lhs_type, rhs_type); case IMPLIES: case IFF: checkIsSubtype(SemanticType.Bool, lhs_type, e.leftOperand); checkIsSubtype(SemanticType.Bool, rhs_type, e.rightOperand); return SemanticType.Bool; case LT: case LTEQ: case GT: case GTEQ: checkIsSubtype(SemanticType.IntOrReal, lhs_type, e.leftOperand); checkIsSubtype(SemanticType.IntOrReal, rhs_type, e.rightOperand); return SemanticType.Or(lhs_type, rhs_type); case IN: { checkIsSubtype(SemanticType.SetAny, rhs_type, e.rightOperand); SemanticType.Set s = (SemanticType.Set) rhs_type; return s; } case SUBSET: case SUBSETEQ: case SUPSET: case SUPSETEQ: { checkIsSubtype(SemanticType.SetAny, lhs_type, e.leftOperand); checkIsSubtype(SemanticType.SetAny, rhs_type, e.rightOperand); // following can cause some problems // checkIsSubtype(lhs_type,rhs_type,e); return SemanticType.Or(lhs_type, rhs_type); } case SETUNION: { checkIsSubtype(SemanticType.SetAny, lhs_type, e.leftOperand); checkIsSubtype(SemanticType.SetAny, rhs_type, e.rightOperand); SemanticType.Set l = (SemanticType.Set) lhs_type; SemanticType.Set r = (SemanticType.Set) rhs_type; return SemanticType.Set(true, SemanticType.Or(l.element(), r.element())); } case SETINTERSECTION: { checkIsSubtype(SemanticType.SetAny, lhs_type, e.leftOperand); checkIsSubtype(SemanticType.SetAny, rhs_type, e.rightOperand); // TODO: the following gives a more accurate type, but there are // some outstanding issues related to the type system reduction // rules. // return SemanticType.And(lhs_type,rhs_type); SemanticType.Set l = (SemanticType.Set) lhs_type; SemanticType.Set r = (SemanticType.Set) rhs_type; return SemanticType.Set(true, SemanticType.Or(l.element(), r.element())); } case LISTAPPEND: { checkIsSubtype(SemanticType.SetTupleAnyAny, lhs_type, e.leftOperand); checkIsSubtype(SemanticType.SetTupleAnyAny, rhs_type, e.rightOperand); SemanticType.Set l = (SemanticType.Set) lhs_type; SemanticType.Set r = (SemanticType.Set) rhs_type; return SemanticType.Set(true, SemanticType.Or(l.element(), r.element())); } case RANGE: { checkIsSubtype(SemanticType.Int, lhs_type, e.leftOperand); checkIsSubtype(SemanticType.Int, rhs_type, e.rightOperand); return SemanticType.Set(true, SemanticType.Tuple(SemanticType.Int, SemanticType.Int)); } } internalFailure("unknown binary expression encountered (" + e + ")", filename, e); return null; // deadcode }