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.Nary e, HashMap<String, SemanticType> environment, HashSet<String> generics, WyalFile.Context context) { Expr[] e_operands = e.operands; SemanticType[] op_types = new SemanticType[e_operands.length]; for (int i = 0; i != e_operands.length; ++i) { op_types[i] = propagate(e_operands[i], environment, generics, context); } switch (e.op) { case AND: case OR: for (int i = 0; i != e_operands.length; ++i) { checkIsSubtype(SemanticType.Bool, op_types[i], e_operands[i]); } return SemanticType.Bool; case TUPLE: return SemanticType.Tuple(op_types); case SET: if (op_types.length == 0) { return SemanticType.Set(true, SemanticType.Void); } else { return SemanticType.Set(true, SemanticType.Or(op_types)); } case LIST: if (op_types.length == 0) { return SemanticType.Set(true, SemanticType.Void); } else { return SemanticType.Set( true, SemanticType.Tuple(SemanticType.Int, SemanticType.Or(op_types))); } } internalFailure("unknown nary expression encountered (" + e + ")", filename, e); return null; // deadcode }
/** * Check that t1 :> t2 or, equivalently, that t2 is a subtype of t1. A type * <code>t1</code> is said to be a subtype of another type <code>t2</code> * iff the semantic set described by <code>t1</code> contains that described * by <code>t2</code>. * * @param t1 * --- Semantic type that should contain <code>t2</code>. * @param t2 * --- Semantic type that shold be contained by <code>t1/code>. * @param element * --- Syntax error is reported against this element if * <code>t1</code> does not contain <code>t2</code>. */ private void checkIsSubtype(SemanticType t1, SemanticType t2, SyntacticElement element) { if (!SemanticType.isSubtype(t1, t2)) { syntaxError("expected type " + t1 + ", got type " + t2, filename, element); } }
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 }