diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-01-15 19:14:58 +0200 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-01-15 19:25:59 +0200 |
| commit | 7eaa051d4dcc3048c46f302997fd2175a983ac0e (patch) | |
| tree | 7734373551b8d0ac87a2857965fbc63067df1006 /src/lower.c | |
| parent | 164625327bd057141edf84339d4b43b2a8e2de24 (diff) | |
| download | ek-7eaa051d4dcc3048c46f302997fd2175a983ac0e.tar.gz ek-7eaa051d4dcc3048c46f302997fd2175a983ac0e.zip | |
improve generics expansion
Diffstat (limited to 'src/lower.c')
| -rw-r--r-- | src/lower.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/src/lower.c b/src/lower.c index e6c147f..8aefd68 100644 --- a/src/lower.c +++ b/src/lower.c @@ -196,6 +196,11 @@ typedef int (*visit_struct_t)(struct lower_state *s, struct ast *n, size_t o, static ssize_t visit_struct(struct lower_state *s, struct ast *def, size_t base, visit_struct_t cb, void *data) { + /* I believe we're only interested in the variables, so find them at the + * root of the chain */ + if (def->chain) + return visit_struct(s, def->chain, base, cb, data); + size_t offset = (size_t)base; foreach_node(n, struct_body(def)) { if (n->k != AST_VAR_DEF) @@ -879,12 +884,49 @@ static int lower_call(struct lower_state *s, struct ast *c, assert(c->k == AST_CALL); struct retval call = retval_create(); + if (ast_flags(c, AST_FLAG_UFCS_SIMPLE) + || ast_flags(c, AST_FLAG_UFCS_REF) + || ast_flags(c, AST_FLAG_UFCS_TRIVIAL)) { + struct ast *dot = call_expr(c); + assert(dot && dot->k == AST_DOT); + + struct ast *expr = dot_expr(dot); + + char *id = strdup(dot_id(dot)); + assert(id); + + struct ast *fetch = gen_fetch(id, clone_type(expr->t), + dot->loc); + assert(fetch); + + fetch->t = clone_type(dot->t); + call_expr(c) = fetch; + + if (!ast_flags(c, AST_FLAG_UFCS_TRIVIAL)) { + struct ast *arg = expr; + if (ast_flags(c, AST_FLAG_UFCS_REF)) { + arg = gen_unop(AST_REF, expr, dot->loc); + arg->t = clone_type(expr->t); + /** @todo should simplify refderef here */ + } + + /* prepend new arg to list */ + arg->n = call_args(c); + call_args(c) = arg; + } + } + if (lower_expr(s, call_expr(c), &call)) { retval_destroy(&call); return -1; } - struct type *rtype = callable_rtype((call_expr(c))->t); + struct ast *expr = call_expr(c); + struct type *callable = expr->t; + if (callable->k == TYPE_PTR) + callable = ptr_base(callable); + + struct type *rtype = callable_rtype(callable); char *rbuf = NULL; if (rtype->k == TYPE_STRUCT) { rbuf = build_str("rbuf_%zd", s->uniq++); |
