stage1 修复错误 提供类型检查

This commit is contained in:
zzy
2026-07-22 18:04:35 +08:00
parent a2d5dd9ce8
commit da9dae734c
5 changed files with 136 additions and 30 deletions

View File

@@ -609,24 +609,107 @@ static int parse_call_args(spl_comp_t *ctx) {
return nargs;
}
static int types_equal(spl_type_ctx_t *tctx, int a, int b) {
if (a < 0 || b < 0)
return 0;
a = spl_type_resolve_underlying(tctx, a);
b = spl_type_resolve_underlying(tctx, b);
if (a == b)
return 1;
spl_type_kind_t ak = spl_type_kind(tctx, a);
spl_type_kind_t bk = spl_type_kind(tctx, b);
if (ak != bk)
return 0;
switch (ak) {
case TYPE_VOID:
return 1;
case TYPE_BASIC:
return spl_type_basic_type(tctx, a) == spl_type_basic_type(tctx, b);
case TYPE_PTR:
return types_equal(tctx, spl_type_elem_type(tctx, a), spl_type_elem_type(tctx, b));
case TYPE_ARRAY:
return spl_type_array_len(tctx, a) == spl_type_array_len(tctx, b) &&
types_equal(tctx, spl_type_elem_type(tctx, a), spl_type_elem_type(tctx, b));
case TYPE_SLICE:
return types_equal(tctx, spl_type_elem_type(tctx, a), spl_type_elem_type(tctx, b));
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ENUM: {
const char *an = spl_type_name(tctx, a);
const char *bn = spl_type_name(tctx, b);
return an && bn && strcmp(an, bn) == 0;
}
default:
return 0;
}
}
static void spl_check_arg_type(spl_comp_t *ctx, const char *fname, int arg_type_idx,
int param_type_idx, int arg_idx) {
if (arg_type_idx < 0 || param_type_idx < 0)
return;
if (spl_type_kind(&ctx->tctx, param_type_idx) == TYPE_PTR &&
spl_type_elem_type(&ctx->tctx, param_type_idx) >= 0 &&
spl_type_kind(&ctx->tctx, arg_type_idx) != TYPE_PTR &&
spl_type_name(&ctx->tctx, arg_type_idx) &&
spl_type_name(&ctx->tctx, spl_type_elem_type(&ctx->tctx, param_type_idx)) &&
strcmp(spl_type_name(&ctx->tctx, arg_type_idx),
spl_type_name(&ctx->tctx, spl_type_elem_type(&ctx->tctx, param_type_idx))) == 0) {
fprintf(stderr,
"%s: warning: argument %d of '%s' expects '%s*', "
"got '%s' (missing '&'?)\n",
ctx->fname, arg_idx + 1, fname,
spl_type_name(&ctx->tctx, spl_type_elem_type(&ctx->tctx, param_type_idx)),
spl_type_name(&ctx->tctx, arg_type_idx));
/* Level 1: structurally equal types */
if (types_equal(&ctx->tctx, arg_type_idx, param_type_idx))
return;
int arg_u = spl_type_resolve_underlying(&ctx->tctx, arg_type_idx);
int param_u = spl_type_resolve_underlying(&ctx->tctx, param_type_idx);
/* Level 1b: void pointer (*_) accepts any pointer */
if (spl_type_kind(&ctx->tctx, param_u) == TYPE_PTR) {
int param_elem = spl_type_elem_type(&ctx->tctx, param_u);
int param_elem_u = spl_type_resolve_underlying(&ctx->tctx, param_elem);
if (param_elem_u >= 0 && spl_type_kind(&ctx->tctx, param_elem_u) == TYPE_BASIC &&
spl_type_basic_type(&ctx->tctx, param_elem_u) == SPL_VOID &&
spl_type_kind(&ctx->tctx, arg_u) == TYPE_PTR) {
return;
}
}
/* Level 2: pointer indirection mismatch with same inner type */
if (spl_type_kind(&ctx->tctx, param_u) == TYPE_PTR) {
int param_elem = spl_type_elem_type(&ctx->tctx, param_u);
if (param_elem < 0)
goto type_mismatch;
/* 2a: param = *T, arg = T (missing '&') */
if (spl_type_kind(&ctx->tctx, arg_u) != TYPE_PTR) {
if (types_equal(&ctx->tctx, arg_type_idx, param_elem)) {
const char *is = spl_type_str(&ctx->tctx, param_elem);
fprintf(stderr,
"%s: warning: argument %d of '%s' expects '%s*', "
"got '%s' (missing '&'?)\n",
ctx->fname, arg_idx + 1, fname, is, is);
return;
}
}
/* 2b: param = *T, arg = **T (extra '&') */
if (spl_type_kind(&ctx->tctx, arg_u) == TYPE_PTR) {
int arg_elem = spl_type_elem_type(&ctx->tctx, arg_u);
int arg_elem_u = spl_type_resolve_underlying(&ctx->tctx, arg_elem);
if (spl_type_kind(&ctx->tctx, arg_elem_u) == TYPE_PTR) {
if (types_equal(&ctx->tctx, spl_type_elem_type(&ctx->tctx, arg_elem), param_elem)) {
const char *is = spl_type_str(&ctx->tctx, param_elem);
fprintf(stderr,
"%s: warning: argument %d of '%s' expects '%s*', "
"got '%s**' (extra '&'?)\n",
ctx->fname, arg_idx + 1, fname, is, is);
return;
}
}
}
}
/* Level 3: general type mismatch → error */
type_mismatch:;
const char *as = spl_type_str(&ctx->tctx, arg_type_idx);
const char *ps = spl_type_str(&ctx->tctx, param_type_idx);
spl_comp_error(ctx, "argument %d of '%s' type mismatch: expected '%s', got '%s'", arg_idx + 1,
fname, ps, as);
}
static int parse_call_args_checked(spl_comp_t *ctx, const char *fname, int *param_type_indices,
@@ -975,6 +1058,10 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
}
expect(ctx, TOK_R_PAREN);
if (func->func_idx < 0) {
fprintf(stderr, "WARN: method call '%s.' with invalid func_idx=%d\n",
func->name, func->func_idx);
}
emit_call_with_fixup(&ctx->emit, nargs, func->func_idx);
left = (spl_expr_result_t){func->ret_type_idx, 0};