diff --git a/compile.c b/compile.c index 3f25f5f..dcb180a 100644 --- a/compile.c +++ b/compile.c @@ -56,6 +56,11 @@ static bool promote(env_t *env, CORD *code, type_t *actual, type_t *needed) return true; } + if (needed->tag == FunctionType && actual->tag == FunctionType) { + *code = CORD_all("(", compile_type(env, needed), ")", *code); + return true; + } + return false; } @@ -1710,7 +1715,10 @@ CORD compile(env_t *env, ast_t *ast) binding_t *b = get_namespace_binding(env, impl, field->name); if (b) { // TODO: typecheck implementation! - c = CORD_all(c, ", (void*)", b->code); + CORD field_code = b->code; + if (!promote(env, &field_code, b->type, field->type)) + code_err(ast, "I can't promote the method '%s' from %T to %T", field->name, b->type, field->type); + c = CORD_all(c, ", ", field_code); } else { type_t *member_t = get_field_type(impl_t, field->name); if (!member_t) diff --git a/types.c b/types.c index 85060b4..ca0f77f 100644 --- a/types.c +++ b/types.c @@ -270,6 +270,19 @@ bool can_promote(type_t *actual, type_t *needed) if (needed->tag == ClosureType && actual->tag == FunctionType) return type_eq(actual, Match(needed, ClosureType)->fn); + if (actual->tag == FunctionType && needed->tag == FunctionType) { + for (arg_t *actual_arg = Match(actual, FunctionType)->args, *needed_arg = Match(needed, FunctionType)->args; + actual_arg || needed_arg; actual_arg = actual_arg->next, needed_arg = needed_arg->next) { + if (!actual_arg || !needed_arg) return false; + if (type_eq(actual_arg->type, needed_arg->type)) continue; + if (actual_arg->type->tag == PointerType && needed_arg->type->tag == PointerType + && can_promote(actual_arg->type, needed_arg->type)) + continue; + return false; + } + return true; + } + return false; }