diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-02-20 17:13:50 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-02-20 17:13:50 -0500 |
| commit | 91f66d80bb308b9aeca3b74b72e1593539c38862 (patch) | |
| tree | 8a017837c51dd71d1467ffffeaf9eb361e191291 /typecheck.c | |
| parent | 43a2959be3835fac0b39ae1be3a9116b5ec184f0 (diff) | |
Support arbitrary argument constructors
Diffstat (limited to 'typecheck.c')
| -rw-r--r-- | typecheck.c | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/typecheck.c b/typecheck.c index cbdbc8cd..26a8ff9f 100644 --- a/typecheck.c +++ b/typecheck.c @@ -791,7 +791,11 @@ type_t *get_type(env_t *env, ast_t *ast) if (fn_type_t->tag == TypeInfoType) { type_t *t = Match(fn_type_t, TypeInfoType)->type; - if (t->tag == StructType || t->tag == IntType || t->tag == BigIntType || t->tag == NumType + + binding_t *constructor = get_constructor(env, t, call->args); + if (constructor) + return t; + else if (t->tag == StructType || t->tag == IntType || t->tag == BigIntType || t->tag == NumType || t->tag == ByteType || t->tag == TextType || t->tag == CStringType || t->tag == MomentType) return t; // Constructor code_err(call->fn, "This is not a type that has a constructor"); @@ -1363,6 +1367,58 @@ type_t *get_arg_type(env_t *env, arg_t *arg) return get_type(env, arg->default_val); } +bool is_valid_call(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bool promotion_allowed) +{ + Table_t used_args = {}; + for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) { + type_t *spec_type = get_arg_type(env, spec_arg); + int64_t i = 1; + // Find keyword: + if (spec_arg->name) { + for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) { + if (call_arg->name && streq(call_arg->name, spec_arg->name)) { + type_t *call_type = get_arg_ast_type(env, call_arg); + if (!(type_eq(call_type, spec_type) || (promotion_allowed && can_promote(call_type, spec_type)))) + return false; + Table$str_set(&used_args, call_arg->name, call_arg); + goto found_it; + } + } + } + // Find positional: + for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) { + if (call_arg->name) continue; + const char *pseudoname = heap_strf("%ld", i++); + if (!Table$str_get(used_args, pseudoname)) { + type_t *call_type = get_arg_ast_type(env, call_arg); + if (!(type_eq(call_type, spec_type) || (promotion_allowed && can_promote(call_type, spec_type)))) + return false; + Table$str_set(&used_args, pseudoname, call_arg); + goto found_it; + } + } + + if (spec_arg->default_val) + goto found_it; + + return false; + found_it: continue; + } + + int64_t i = 1; + for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) { + if (call_arg->name) { + if (!Table$str_get(used_args, call_arg->name)) + return false; + } else { + const char *pseudoname = heap_strf("%ld", i++); + if (!Table$str_get(used_args, pseudoname)) + return false; + } + } + return true; +} + PUREFUNC bool can_be_mutated(env_t *env, ast_t *ast) { switch (ast->tag) { |
