// Determine the UIF types that the given type may be static int uifset(pass_opt_t* opt, ast_t* type, lit_chain_t* chain) { assert(chain != NULL); if(is_typecheck_error(type)) return UIF_NO_TYPES; switch(ast_id(type)) { case TK_UNIONTYPE: return uifset_union(opt, type, chain); case TK_ISECTTYPE: return uifset_intersect(opt, type, chain); case TK_ARROW: // Since we don't care about capabilities we can just use the rhs assert(ast_id(ast_childidx(type, 1)) == TK_NOMINAL); return uifset(opt, ast_childidx(type, 1), chain); case TK_TYPEPARAMREF: if(chain->cardinality != CHAIN_CARD_BASE) // Incorrect cardinality return UIF_NO_TYPES; return uifset_formal_param(opt, type, chain); case TK_TUPLETYPE: if(chain->cardinality != ast_childcount(type)) // Incorrect cardinality return UIF_NO_TYPES; return uifset(opt, ast_childidx(type, chain->index), chain->next); case TK_NOMINAL: if(strcmp(ast_name(ast_childidx(type, 1)), "Array") == 0) { if(chain->cardinality != CHAIN_CARD_ARRAY) // Incorrect cardinality return UIF_NO_TYPES; ast_t* type_args = ast_childidx(type, 2); assert(ast_childcount(type_args) == 1); return uifset(opt, ast_child(type_args), chain->next); } if(chain->cardinality != CHAIN_CARD_BASE) // Incorrect cardinality return UIF_NO_TYPES; return uifset_simple_type(opt, type); default: ast_error(type, "Internal error: uif type, node %d", ast_id(type)); assert(0); return UIF_ERROR; } }
// Determine the UIF types that the given non-tuple union type may be static int uifset_union(pass_opt_t* opt, ast_t* type, lit_chain_t* chain) { assert(type != NULL); assert(ast_id(type) == TK_UNIONTYPE); int uif_set = 0; // Process all elements of the union for(ast_t* p = ast_child(type); p != NULL; p = ast_sibling(p)) { int r = uifset(opt, p, chain); if(r == UIF_ERROR) // Propogate errors return UIF_ERROR; bool child_valid = (r != UIF_NO_TYPES); bool child_formal = ((r & UIF_CONSTRAINED) != 0); bool others_valid = ((uif_set & UIF_ALL_TYPES) != 0); bool others_formal = ((uif_set & UIF_CONSTRAINED) != 0); if(child_valid && others_valid && (child_formal != others_formal)) { // We're unioning a formal parameter and a UIF type, not allowed ast_error(type, "Could not infer literal type, ambiguous union"); return UIF_ERROR; } uif_set |= r; } return uif_set; }
// Fill the given UIF type cache static bool uif_type(pass_opt_t* opt, ast_t* literal, ast_t* type, lit_chain_t* chain_head, bool report_errors) { pony_assert(chain_head != NULL); pony_assert(chain_head->cardinality == CHAIN_CARD_BASE); chain_head->formal = NULL; int r = uifset(opt, type, chain_head->next); if(r == UIF_ERROR) return false; if(r == UIF_NO_TYPES) { if(report_errors) ast_error(opt->check.errors, literal, "could not infer literal type, no valid types found"); return false; } pony_assert(type != NULL); if((r & UIF_CONSTRAINED) != 0) { // Type is a formal parameter pony_assert(chain_head->formal != NULL); pony_assert(chain_head->name != NULL); pony_assert(chain_head->cached_uif_index < 0); BUILD(uif_type, type, NODE(TK_TYPEPARAMREF, DATA(chain_head->formal) ID(chain_head->name) NODE(TK_VAL) NONE)); chain_head->cached_type = uif_type; chain_head->valid_for_float = ((r & UIF_INT_MASK) == 0); return true; } // Type is one or more UIFs for(int i = 0; i < UIF_COUNT; i++) { if(r == (1 << i)) { chain_head->valid_for_float = (((1 << i) & UIF_INT_MASK) == 0); chain_head->cached_type = type_builtin(opt, type, _str_uif_types[i].name); //ast_setid(ast_childidx(chain_head->cached_type, 4), TK_EPHEMERAL); chain_head->name = _str_uif_types[i].name; chain_head->cached_uif_index = i; return true; } } ast_error(opt->check.errors, literal, "Multiple possible types for literal"); return false; }
// Determine the UIF types that the given non-tuple intersection type may be static int uifset_intersect(pass_opt_t* opt, ast_t* type, lit_chain_t* chain) { assert(type != NULL); assert(ast_id(type) == TK_ISECTTYPE); int uif_set = UIF_ALL_TYPES; int constraint = 0; for(ast_t* p = ast_child(type); p != NULL; p = ast_sibling(p)) { int r = uifset(opt, p, chain); if(r == UIF_ERROR) // Propogate errors return UIF_ERROR; if((r & UIF_CONSTRAINED) != 0) { // We have a formal parameter constraint = r; } else { uif_set |= r; } } if(constraint != 0) { // We had a formal parameter int constraint_set = constraint & UIF_ALL_TYPES; if((constraint_set & uif_set) != constraint_set) // UIF type limits formal parameter types, no UIF guaranteed return UIF_NO_TYPES; return constraint; } return uif_set; }