// Unify all the branches of the given AST to the same type static bool unify(ast_t* ast, pass_opt_t* options, bool report_errors) { assert(ast != NULL); ast_t* type = ast_type(ast); if(is_typecheck_error(type)) return false; if(!is_type_literal(type)) // Not literal, nothing to unify return true; assert(type != NULL); ast_t* non_literal = ast_type(type); if(non_literal != NULL) { // Type has a non-literal element, coerce literals to that lit_chain_t chain; chain_init_head(&chain); return coerce_literal_to_type(&ast, non_literal, &chain, options, report_errors); //return coerce_literals(&ast, non_literal, options); } // Still a pure literal return true; }
// Coerce a literal group (tuple or array) to be the specified target type static bool coerce_group(ast_t** astp, ast_t* target_type, lit_chain_t* chain, size_t cardinality, pass_opt_t* options, bool report_errors) { pony_assert(astp != NULL); ast_t* literal_expr = *astp; pony_assert(literal_expr != NULL); pony_assert(ast_id(literal_expr) == TK_TUPLE || ast_id(literal_expr) == TK_ARRAY); pony_assert(chain != NULL); pony_assert(cardinality != CHAIN_CARD_BASE); size_t i = 0; lit_chain_t link; chain_add(chain, &link, cardinality); if(ast_id(literal_expr) == TK_ARRAY) { // The first child of an array AST is the forced type, the second child is // the sequence of elements. literal_expr = ast_childidx(literal_expr, 1); } // Process each group element separately for(ast_t* p = ast_child(literal_expr); p != NULL; p = ast_sibling(p)) { ast_t* p_type = ast_type(p); if(is_typecheck_error(p_type)) return false; if(is_type_literal(p_type)) { // This element is a literal if(cardinality != CHAIN_CARD_ARRAY) { chain_clear_cache(&link); link.index = i; } if(!coerce_literal_to_type(&p, target_type, &link, options, report_errors)) return false; } i++; } chain_remove(chain); return true; }
// Coerce a literal control block to be the specified target type static bool coerce_control_block(ast_t** astp, ast_t* target_type, lit_chain_t* chain, pass_opt_t* options, bool report_errors) { assert(astp != NULL); ast_t* literal_expr = *astp; assert(literal_expr != NULL); ast_t* lit_type = ast_type(literal_expr); assert(lit_type != NULL); assert(ast_id(lit_type) == TK_LITERAL); ast_t* block_type = ast_type(lit_type); for(ast_t* p = ast_child(lit_type); p != NULL; p = ast_sibling(p)) { assert(ast_id(p) == TK_LITERALBRANCH); ast_t* branch = (ast_t*)ast_data(p); assert(branch != NULL); if(!coerce_literal_to_type(&branch, target_type, chain, options, report_errors)) { ast_free_unattached(block_type); return false; } block_type = type_union(block_type, ast_type(branch)); } if(is_typecheck_error(block_type)) return false; // block_type may be a sub-tree of the current type of literal_expr. // This means we must copy it before setting it as the type since ast_settype // will first free the existing type of literal_expr, which may include // block_type. if(ast_parent(block_type) != NULL) block_type = ast_dup(block_type); ast_settype(literal_expr, block_type); return true; }
bool coerce_literals(ast_t** astp, ast_t* target_type, pass_opt_t* options) { assert(astp != NULL); ast_t* literal_expr = *astp; assert(literal_expr != NULL); if(ast_id(literal_expr) == TK_NONE) return true; ast_t* lit_type = ast_type(literal_expr); if(lit_type != NULL && ast_id(lit_type) != TK_LITERAL && ast_id(lit_type) != TK_OPERATORLITERAL) return true; if(target_type == NULL && !unify(literal_expr, options, true)) return false; lit_chain_t chain; chain_init_head(&chain); return coerce_literal_to_type(astp, target_type, &chain, options, true); }
// Coerce a literal expression to given tuple or non-tuple types static bool coerce_literal_to_type(ast_t** astp, ast_t* target_type, lit_chain_t* chain, pass_opt_t* options, bool report_errors) { assert(astp != NULL); ast_t* literal_expr = *astp; assert(literal_expr != NULL); ast_t* lit_type = ast_type(literal_expr); if(lit_type == NULL || (ast_id(lit_type) != TK_LITERAL && ast_id(lit_type) != TK_OPERATORLITERAL)) { // Not a literal return true; } if(ast_child(lit_type) != NULL) { // Control block literal return coerce_control_block(astp, target_type, chain, options, report_errors); } switch(ast_id(literal_expr)) { case TK_TUPLE: // Tuple literal { size_t cardinality = ast_childcount(literal_expr); if(!coerce_group(astp, target_type, chain, cardinality, options, report_errors)) return false; break; } case TK_INT: return uif_type_from_chain(options, literal_expr, target_type, chain, false, report_errors); case TK_FLOAT: return uif_type_from_chain(options, literal_expr, target_type, chain, true, report_errors); case TK_ARRAY: if(!coerce_group(astp, target_type, chain, CHAIN_CARD_ARRAY, options, report_errors)) return false; break; case TK_SEQ: { // Only coerce the last expression in the sequence ast_t* last = ast_childlast(literal_expr); if(!coerce_literal_to_type(&last, target_type, chain, options, report_errors)) return false; ast_settype(literal_expr, ast_type(last)); return true; } case TK_CALL: { AST_GET_CHILDREN(literal_expr, positional, named, receiver); ast_t* arg = ast_child(positional); if(!coerce_literal_to_type(&receiver, target_type, chain, options, report_errors)) return false; if(arg != NULL && !coerce_literal_to_type(&arg, target_type, chain, options, report_errors)) return false; ast_settype(literal_expr, ast_type(ast_child(receiver))); return true; } case TK_DOT: { ast_t* receiver = ast_child(literal_expr); if(!coerce_literal_to_type(&receiver, target_type, chain, options, report_errors)) return false; break; } default: ast_error(literal_expr, "Internal error, coerce_literal_to_type node %s", ast_get_print(literal_expr)); assert(0); return false; } // Need to reprocess node now all the literals have types ast_settype(literal_expr, NULL); return (pass_expr(astp, options) == AST_OK); }