cgen: fix free method for option fields (#22070)

This commit is contained in:
Felipe Pena 2024-08-19 11:25:07 -03:00 committed by GitHub
parent fbc34741cc
commit e7c2295f64
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 61 additions and 4 deletions

View File

@ -30,7 +30,7 @@ fn (mut g Gen) gen_free_methods() {
fn (mut g Gen) gen_free_method(typ ast.Type) string {
styp := g.typ(typ).replace('*', '')
mut fn_name := styp_to_free_fn_name(styp)
deref_typ := typ.set_nr_muls(0)
deref_typ := if typ.has_flag(.option) { typ } else { typ.set_nr_muls(0) }
if deref_typ in g.generated_free_methods {
return fn_name
}
@ -81,7 +81,8 @@ fn (mut g Gen) gen_free_for_struct(typ ast.Type, info ast.Struct, styp string, f
if sym.kind !in [.string, .array, .map, .struct_] {
continue
}
mut field_styp := g.typ(field.typ).replace('*', '')
mut field_styp := g.typ(field.typ.set_nr_muls(0).clear_flag(.option)).replace('*',
'')
is_shared := field_styp.starts_with('__shared')
is_struct_option := typ.has_flag(.option)
if is_shared {
@ -92,16 +93,36 @@ fn (mut g Gen) gen_free_for_struct(typ ast.Type, info ast.Struct, styp string, f
} else {
g.gen_free_method(field.typ)
}
is_field_option := field.typ.has_flag(.option)
expects_opt := field_styp_fn_name.starts_with('_option_')
if is_shared {
fn_builder.writeln('\t${field_styp_fn_name}(&(it->${field_name}->val));')
} else if is_struct_option {
opt_styp := g.base_type(typ)
prefix := if field.typ.is_ptr() { '' } else { '&' }
if is_field_option {
opt_field_styp := if expects_opt { g.typ(field.typ) } else { g.base_type(field.typ) }
suffix := if expects_opt { '' } else { '.data' }
fn_builder.writeln('\tif (((${opt_styp}*)&it->data)->${field_name}.state != 2) {')
fn_builder.writeln('\t\t${field_styp_fn_name}((${opt_field_styp}*)${prefix}((${opt_styp}*)&it->data)->${field_name}${suffix});')
fn_builder.writeln('\t}')
} else {
fn_builder.writeln('\t${field_styp_fn_name}(${prefix}((${opt_styp}*)&it->data)->${field_name});')
}
} else {
if is_field_option {
opt_field_styp := if expects_opt { g.typ(field.typ) } else { g.base_type(field.typ) }
suffix := if expects_opt { '' } else { '.data' }
fn_builder.writeln('\tif (it->${field_name}.state != 2) {')
fn_builder.writeln('\t\t${field_styp_fn_name}((${opt_field_styp}*)&(it->${field_name}${suffix}));')
fn_builder.writeln('\t}')
} else {
fn_builder.writeln('\t${field_styp_fn_name}(&(it->${field_name}));')
}
}
}
fn_builder.writeln('}')
}

View File

@ -0,0 +1,36 @@
pub struct Test2 {
a int
}
pub struct Test {
a Test2
b ?string
c ?Test2
d ?&Test2
}
@[manualfree]
fn test_main() {
t := Test{
b: 'b'
}
println('t: ${t}')
defer {
unsafe {
t.free()
}
}
mut t2 := ?Test(Test{
b: 'b'
})
println('t: ${t2}')
defer {
unsafe {
t2?.free()
}
}
}