static bool method_application(pass_opt_t* opt, ast_t* ast, bool partial) { // TODO: use args to decide unbound type parameters AST_GET_CHILDREN(ast, positional, namedargs, lhs); if(!check_type_params(&lhs)) return false; ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; AST_GET_CHILDREN(type, cap, typeparams, params, result); if(!extend_positional_args(params, positional)) return false; if(!apply_named_args(params, positional, namedargs)) return false; bool incomplete = is_this_incomplete(&opt->check, ast); if(!check_arg_types(opt, params, positional, incomplete, partial)) return false; switch(ast_id(lhs)) { case TK_FUNREF: case TK_FUNAPP: if(!check_receiver_cap(ast, incomplete)) return false; break; default: {} } return true; }
bool expr_this(pass_opt_t* opt, ast_t* ast) { typecheck_t* t = &opt->check; if(t->frame->def_arg != NULL) { ast_error(opt->check.errors, ast, "can't reference 'this' in a default argument"); return false; } sym_status_t status; ast_get(ast, stringtab("this"), &status); if(status == SYM_CONSUMED) { ast_error(opt->check.errors, ast, "can't use a consumed 'this' in an expression"); return false; } assert(status == SYM_NONE); token_id cap = cap_for_this(t); if(!cap_sendable(cap) && (t->frame->recover != NULL)) { ast_t* parent = ast_parent(ast); if(ast_id(parent) != TK_DOT) cap = TK_TAG; } bool make_arrow = false; if(cap == TK_BOX) { cap = TK_REF; make_arrow = true; } ast_t* type = type_for_this(opt, ast, cap, TK_NONE, false); if(make_arrow) { BUILD(arrow, ast, NODE(TK_ARROW, NODE(TK_THISTYPE) TREE(type))); type = arrow; } // Get the nominal type, which may be the right side of an arrow type. ast_t* nominal; bool arrow; if(ast_id(type) == TK_NOMINAL) { nominal = type; arrow = false; } else { nominal = ast_childidx(type, 1); arrow = true; } ast_t* typeargs = ast_childidx(nominal, 2); ast_t* typearg = ast_child(typeargs); while(typearg != NULL) { if(!expr_nominal(opt, &typearg)) { ast_error(opt->check.errors, ast, "couldn't create a type for 'this'"); ast_free(type); return false; } typearg = ast_sibling(typearg); } if(!expr_nominal(opt, &nominal)) { ast_error(opt->check.errors, ast, "couldn't create a type for 'this'"); ast_free(type); return false; } // Unless this is a field lookup, treat an incomplete `this` as a tag. ast_t* parent = ast_parent(ast); bool incomplete_ok = false; if((ast_id(parent) == TK_DOT) && (ast_child(parent) == ast)) { ast_t* right = ast_sibling(ast); assert(ast_id(right) == TK_ID); ast_t* find = lookup_try(opt, ast, nominal, ast_name(right)); if(find != NULL) { switch(ast_id(find)) { case TK_FVAR: case TK_FLET: case TK_EMBED: incomplete_ok = true; break; default: {} } } } if(!incomplete_ok && is_this_incomplete(t, ast)) { ast_t* tag_type = set_cap_and_ephemeral(nominal, TK_TAG, TK_NONE); ast_replace(&nominal, tag_type); } if(arrow) type = ast_parent(nominal); else type = nominal; ast_settype(ast, type); return true; }
bool expr_return(pass_opt_t* opt, ast_t* ast) { typecheck_t* t = &opt->check; // return is always the last expression in a sequence assert(ast_sibling(ast) == NULL); if(ast_parent(ast) == t->frame->method_body) { ast_error(ast, "use return only to exit early from a method, not at the end"); return false; } ast_t* type = ast_childidx(t->frame->method, 4); ast_t* body = ast_child(ast); if(!coerce_literals(&body, type, opt)) return false; ast_t* body_type = ast_type(body); if(is_typecheck_error(body_type)) return false; if(is_control_type(body_type)) { ast_error(body, "return value cannot be a control statement"); return false; } bool ok = true; switch(ast_id(t->frame->method)) { case TK_NEW: if(is_this_incomplete(t, ast)) { ast_error(ast, "all fields must be defined before constructor returns"); ok = false; } break; case TK_BE: assert(is_none(body_type)); break; default: { // The body type must be a subtype of the return type, and an alias of // the body type must be a subtype of an alias of the return type. ast_t* a_type = alias(type); ast_t* a_body_type = alias(body_type); errorframe_t info = NULL; if(!is_subtype(body_type, type, &info) || !is_subtype(a_body_type, a_type, &info)) { errorframe_t frame = NULL; ast_t* last = ast_childlast(body); ast_error_frame(&frame, last, "returned value isn't the return type"); ast_error_frame(&frame, type, "function return type: %s", ast_print_type(type)); ast_error_frame(&frame, body_type, "returned value type: %s", ast_print_type(body_type)); errorframe_append(&frame, &info); errorframe_report(&frame); ok = false; } ast_free_unattached(a_type); ast_free_unattached(a_body_type); } } ast_settype(ast, ast_from(ast, TK_RETURN)); ast_inheritflags(ast); return ok; }