cgen: more fixes

This commit is contained in:
Alexander Medvednikov committed 2026-04-20 15:43:07 +03:00
1 parent d503144a37
commit ee64e962b8
7 files changed
+134 -44

No files matched your search

+84 -7
View File
@@ -986,8 +986,25 @@ fn (mut c Checker) symmetric_check(left ast.Type, right ast.Type) bool {
}
fn (c &Checker) generic_type_args_and_parent_idx(typ ast.Type) ([]ast.Type, int) {
base_typ := c.table.fully_unaliased_type(typ.clear_flags().clear_option_and_result())
mut base_typ := c.table.fully_unaliased_type(typ.clear_flags().clear_option_and_result())
if base_typ.nr_muls() > 0 {
base_typ = base_typ.deref()
}
sym := c.table.sym(base_typ)
parse_type_args_from_name := fn [c] (name string) []ast.Type {
if !name.contains('[') || !name.ends_with(']') {
return []ast.Type{}
}
mut parsed := []ast.Type{}
for arg_name in ast.split_generic_args(name.all_after_last('[').trim_right(']')) {
idx := c.table.find_type_idx(arg_name.trim_space())
if idx <= 0 {
return []ast.Type{}
}
parsed << ast.idx_to_type(idx)
}
return parsed
}
match sym.info {
ast.Struct {
mut type_args := sym.info.concrete_types.clone()
@@ -997,7 +1014,12 @@ fn (c &Checker) generic_type_args_and_parent_idx(typ ast.Type) ([]ast.Type, int)
if type_args.len == 0 {
type_args = sym.info.generic_types.clone()
}
parent_idx := if sym.info.parent_type != 0 {
if type_args.len == 0 {
type_args = parse_type_args_from_name(sym.name)
}
parent_idx := if sym.parent_idx > 0 {
sym.parent_idx
} else if sym.info.parent_type != 0 {
sym.info.parent_type.clear_flags().idx()
} else {
base_typ.idx()
@@ -1012,7 +1034,12 @@ fn (c &Checker) generic_type_args_and_parent_idx(typ ast.Type) ([]ast.Type, int)
if type_args.len == 0 {
type_args = sym.info.generic_types.clone()
}
parent_idx := if sym.info.parent_type != 0 {
if type_args.len == 0 {
type_args = parse_type_args_from_name(sym.name)
}
parent_idx := if sym.parent_idx > 0 {
sym.parent_idx
} else if sym.info.parent_type != 0 {
sym.info.parent_type.clear_flags().idx()
} else {
base_typ.idx()
@@ -1027,7 +1054,12 @@ fn (c &Checker) generic_type_args_and_parent_idx(typ ast.Type) ([]ast.Type, int)
if type_args.len == 0 {
type_args = sym.info.generic_types.clone()
}
parent_idx := if sym.info.parent_type != 0 {
if type_args.len == 0 {
type_args = parse_type_args_from_name(sym.name)
}
parent_idx := if sym.parent_idx > 0 {
sym.parent_idx
} else if sym.info.parent_type != 0 {
sym.info.parent_type.clear_flags().idx()
} else {
base_typ.idx()
@@ -1130,8 +1162,30 @@ fn (c &Checker) infer_composite_generic_type(gt_name string, generic_typ ast.Typ
expected_type_args, expected_parent_idx := c.generic_type_args_and_parent_idx(generic_typ)
actual_type_args, actual_parent_idx := c.generic_type_args_and_parent_idx(concrete_typ)
if expected_parent_idx == 0 || expected_parent_idx != actual_parent_idx
|| expected_type_args.len == 0 || expected_type_args.len != actual_type_args.len {
if expected_parent_idx == 0 || actual_parent_idx == 0 || expected_type_args.len == 0
|| expected_type_args.len != actual_type_args.len {
return ast.void_type
}
if expected_parent_idx != actual_parent_idx {
expected_parent_sym := c.table.sym(ast.idx_to_type(expected_parent_idx))
actual_parent_sym := c.table.sym(ast.idx_to_type(actual_parent_idx))
expected_parent_name := if expected_parent_sym.ngname != '' {
expected_parent_sym.ngname
} else {
ast.strip_generic_params(expected_parent_sym.name)
}
actual_parent_name := if actual_parent_sym.ngname != '' {
actual_parent_sym.ngname
} else {
ast.strip_generic_params(actual_parent_sym.name)
}
if expected_parent_name != actual_parent_name
&& expected_parent_sym.parent_idx != actual_parent_idx
&& actual_parent_sym.parent_idx != expected_parent_idx {
return ast.void_type
}
}
if expected_type_args.len == 0 || expected_type_args.len != actual_type_args.len {
return ast.void_type
}
for i, expected_type_arg in expected_type_args {
@@ -1465,7 +1519,6 @@ fn (mut c Checker) infer_fn_generic_types(func &ast.Fn, mut node ast.CallExpr) {
if !param_is_interface && param_sym.kind == .generic_inst {
param_is_interface = c.table.type_symbols[(param_sym.info as ast.GenericInst).parent_idx].kind == .interface
}
if (param_infer_typ.has_flag(.option) && arg.typ.has_flag(.option))
|| (param_infer_typ.has_flag(.result) && arg.typ.has_flag(.result)) {
param_inner := param_infer_typ.clear_option_and_result()
@@ -1669,6 +1722,30 @@ fn (mut c Checker) infer_fn_generic_types(func &ast.Fn, mut node ast.CallExpr) {
break
}
}
if typ == ast.void_type {
typ = c.infer_composite_generic_type(gt_name, param_infer_typ, arg_typ)
if typ == ast.void_type && arg.expr is ast.Ident && arg.expr.obj is ast.Var {
init_expr := arg.expr.obj.expr
if init_expr !is ast.EmptyExpr {
init_typ := match init_expr {
ast.CallExpr {
if init_expr.return_type_generic != 0 {
init_expr.return_type_generic
} else {
init_expr.return_type
}
}
else {
arg.expr.obj.typ
}
}
if init_typ != 0 {
typ = c.infer_composite_generic_type(gt_name, param_infer_typ,
init_typ)
}
}
}
}
}
if typ != ast.void_type {
arg_inferred << arg_i
+13 -26
View File
@@ -1367,8 +1367,8 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
}
g.writeln(';}')
}
} else if node.op == .assign && (is_fixed_array_init
|| (unaliased_right_sym.kind == .array_fixed && val in [ast.Ident, ast.CastExpr])) {
} else if node.op == .assign && (is_fixed_array_init || is_fixed_array_var
|| (unaliased_right_sym.kind == .array_fixed && val is ast.CastExpr)) {
// Fixed arrays
if unaliased_left_sym.kind != .array_fixed && unaliased_right_sym.kind == .array_fixed
&& (g.pref.translated || g.file.is_translated) {
@@ -1399,37 +1399,24 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
g.writeln(', sizeof(${g.styp(var_type)}));')
}
} else {
mut v_var := ''
arr_typ := styp.trim('*')
old_is_assign_lhs := g.is_assign_lhs
g.is_assign_lhs = false
left_expr := g.expr_string(left)
mut fixed_right_expr := ''
if is_fixed_array_init {
right := val as ast.ArrayInit
v_var = g.new_tmp_var()
g.write('${arr_typ} ${v_var} = ')
right_var := g.new_tmp_var()
g.write('${arr_typ} ${right_var} = ')
g.expr(right)
g.writeln(';')
fixed_right_expr = right_var
} else {
v_var = g.expr_string(val)
}
pos := g.out.len
g.expr(left)
if g.is_arraymap_set && g.arraymap_set_pos >= 0 {
if g.arraymap_set_pos > 0 {
g.go_back_to(g.arraymap_set_pos)
}
g.write(', &${v_var})')
g.is_arraymap_set = false
g.arraymap_set_pos = 0
} else {
g.go_back_to(pos)
is_var_mut := !is_decl && left.is_auto_deref_var()
addr_left := if is_var_mut { '' } else { '&' }
g.writeln('')
g.write('memcpy(${addr_left}')
g.expr(left)
addr_val := if is_fixed_array_var { '' } else { '&' }
g.writeln(', ${addr_val}${v_var}, sizeof(${arr_typ}));')
fixed_right_expr = g.expr_string(val)
}
g.is_assign_lhs = old_is_assign_lhs
g.writeln('')
g.writeln('memcpy(${left_expr}, ${fixed_right_expr}, sizeof(${arr_typ}));')
g.is_assign_lhs = false
}
} else {
+14 -6
View File
@@ -4466,15 +4466,11 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
// pointer-backed only when interface semantics require aliasing the
// original storage. Plain value-to-interface conversions still need
// a detached copy, even when the value itself lives in auto-heap storage.
// The exception is values that already came from option/result unwrapping:
// those are already detached heap objects and should be passed through
// directly instead of being wrapped in HEAP(...) a second time.
mut effective_got_is_ptr := got_is_ptr
mut suppress_auto_heap_deref := false
if !got_is_ptr && expr is ast.Ident && g.resolved_ident_is_auto_heap(expr)
&& (g.expected_arg_mut
|| g.interface_cast_requires_field_aliasing(expected_type, expr)
|| g.ident_unwraps_option_or_result(expr)) {
|| g.interface_cast_requires_field_aliasing(expected_type, expr)) {
effective_got_is_ptr = true
suppress_auto_heap_deref = true
}
@@ -9052,6 +9048,14 @@ fn (mut g Gen) return_stmt(node ast.Return) {
type0 = type0.clear_flag(.result)
}
}
if exprs_len > 0 && expr0 is ast.Ident && expr0.obj is ast.Var && expr0.obj.typ != 0 {
resolved_obj_type := g.unwrap_generic(g.recheck_concrete_type(expr0.obj.typ))
if resolved_obj_type != 0 && !resolved_obj_type.has_option_or_result()
&& type0.has_option_or_result()
&& type0.clear_option_and_result() == resolved_obj_type {
type0 = resolved_obj_type
}
}
if exprs_len > 0 {
// `$veb.html()` expands to statements, so the Result return
@@ -11712,7 +11716,11 @@ return ${cast_shared_struct_str};
mut adapter_params := ['void* _x']
for i in 1 .. method.params.len {
arg := method.params[i]
arg_name := if arg.name.len > 0 { c_name(arg.name) } else { 'arg${i}' }
arg_name := if arg.name.len > 0 && arg.name != '_' {
c_name(arg.name)
} else {
'arg${i}'
}
adapter_params << '${g.styp(arg.typ)} ${arg_name}'
adapter_args << arg_name
}
+6 -2
View File
@@ -43,7 +43,11 @@ fn (mut g Gen) comptime_call_expands_string_args(m &ast.Fn, node ast.ComptimeCal
return false
}
array_decompose := node.args.last().expr as ast.ArrayDecompose
if !g.is_string_array_type(array_decompose.expr_type) || m.params.len - 1 < node.args.len {
mut array_type := g.resolved_expr_type(array_decompose.expr, array_decompose.expr_type)
if array_type == ast.void_type {
array_type = array_decompose.expr_type
}
if !g.is_string_array_type(array_type) || m.params.len - 1 < node.args.len {
return false
}
return !g.is_string_array_type(m.params[node.args.len].typ)
@@ -288,7 +292,7 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) {
&& node.args[i - 1].expr is ast.ArrayDecompose {
mut d_count := 0
for d_i in i .. m.params.len {
g.write('*(${g.styp(m.params[i].typ)}*)builtin__array_get(')
g.write('*(${g.styp(m.params[d_i].typ)}*)builtin__array_get(')
g.expr(ast.Expr(node.args[i - 1].expr))
g.write(', ${d_count})')
+5 -2
View File
@@ -741,8 +741,11 @@ fn (mut g Gen) gen_simple_string_inter_literal(node ast.StringInterLiteral, fmts
if i >= node.need_fmts.len || node.need_fmts[i] || i >= fmts.len || fmts[i] == `_` {
return false
}
if node.expr_types[i].is_any_kind_of_pointer() || node.expr_types[i].is_int_valptr()
|| node.expr_types[i].is_float_valptr() {
normalized_expr_type := g.table.fully_unaliased_type(g.unwrap_generic(node.expr_types[i]))
// Pointer aliases need the full `str_intp` path so nil formatting stays
// consistent with plain pointer interpolation.
if normalized_expr_type.is_any_kind_of_pointer() || normalized_expr_type.is_int_valptr()
|| normalized_expr_type.is_float_valptr() {
return false
}
// Interface types need the full str_intp path for vtable dispatch and
+10
View File
@@ -851,6 +851,16 @@ fn (mut g Gen) resolved_expr_type(expr ast.Expr, default_typ ast.Type) ast.Type
mut resolved := g.resolved_expr_type(expr.obj.expr, expr.obj.typ)
if resolved != 0 {
resolved = g.unwrap_generic(g.recheck_concrete_type(resolved))
if expr.obj.typ != 0 {
resolved_obj_type :=
g.unwrap_generic(g.recheck_concrete_type(expr.obj.typ))
if resolved_obj_type != 0
&& !g.type_has_unresolved_generic_parts(resolved_obj_type)
&& resolved.has_option_or_result()
&& resolved.clear_option_and_result() == resolved_obj_type {
return resolved_obj_type
}
}
if g.type_has_unresolved_generic_parts(resolved) {
call_like_type := g.resolved_call_like_expr_type(expr.obj.expr)
if call_like_type != 0 && !call_like_type.has_flag(.generic)
+2 -1
View File
@@ -143,13 +143,14 @@ fn find_tmpl_complex_at_expr_end(line string, start int) int {
for i < line.len && is_tmpl_ident_part(line[i]) {
i++
}
mut has_complex_suffix := false
for i + 1 < line.len && line[i] == `.` && is_tmpl_ident_start(line[i + 1]) {
i += 2
has_complex_suffix = true
for i < line.len && is_tmpl_ident_part(line[i]) {
i++
}
}
mut has_complex_suffix := false
for i < line.len {
if line[i] == `[` {
expr_end := find_tmpl_balanced_end(line, i, `[`, `]`)