checker: simplify unwrap nested selector fix (#23526)

This commit is contained in:
Felipe Pena 2025-01-20 12:28:19 -03:00 committed by GitHub
parent facee322fc
commit 27f637a8dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 91 additions and 35 deletions

View File

@ -926,7 +926,6 @@ pub:
pos token.Pos pos token.Pos
typ Type typ Type
orig_type Type // original sumtype type; 0 if it's not a sumtype orig_type Type // original sumtype type; 0 if it's not a sumtype
pub mut:
smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed
// TODO: move this to a real docs site later // TODO: move this to a real docs site later
// 10 <- original type (orig_type) // 10 <- original type (orig_type)

View File

@ -157,16 +157,6 @@ pub fn (mut s Scope) register_struct_field(name string, field ScopeStructField)
s.struct_fields[name] = field s.struct_fields[name] = field
} }
pub fn (mut s Scope) register_or_update_struct_field(name string, field ScopeStructField) {
if mut f := s.struct_fields[name] {
if f.struct_type == field.struct_type && f.name == field.name {
s.struct_fields[name].smartcasts = field.smartcasts
return
}
}
s.struct_fields[name] = field
}
pub fn (mut s Scope) register(obj ScopeObject) { pub fn (mut s Scope) register(obj ScopeObject) {
if !(obj.name == '_' || obj.name in s.objects) { if !(obj.name == '_' || obj.name in s.objects) {
s.objects[obj.name] = obj s.objects[obj.name] = obj

View File

@ -4286,16 +4286,14 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
orig_type = field.typ orig_type = field.typ
} }
} }
mut nested_unwrap := false expr_str := expr.expr.str()
if mut field := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name) { if mut field := scope.find_struct_field(expr_str, expr.expr_type, expr.field_name) {
smartcasts << field.smartcasts smartcasts << field.smartcasts
nested_unwrap = smartcasts.len > 1
} }
// smartcast either if the value is immutable or if the mut argument is explicitly given // smartcast either if the value is immutable or if the mut argument is explicitly given
if !is_mut || expr.is_mut || is_option_unwrap || orig_type.has_flag(.option) { if !is_mut || expr.is_mut || is_option_unwrap || orig_type.has_flag(.option) {
smartcasts << to_type smartcasts << to_type
if nested_unwrap { scope.register_struct_field(expr_str, ast.ScopeStructField{
scope.register_or_update_struct_field(expr.expr.str(), ast.ScopeStructField{
struct_type: expr.expr_type struct_type: expr.expr_type
name: expr.field_name name: expr.field_name
typ: cur_type typ: cur_type
@ -4303,16 +4301,6 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
pos: expr.pos pos: expr.pos
orig_type: orig_type orig_type: orig_type
}) })
} else {
scope.register_struct_field(expr.expr.str(), ast.ScopeStructField{
struct_type: expr.expr_type
name: expr.field_name
typ: cur_type
smartcasts: smartcasts
pos: expr.pos
orig_type: orig_type
})
}
} else { } else {
c.smartcast_mut_pos = expr.pos c.smartcast_mut_pos = expr.pos
} }

View File

@ -0,0 +1,33 @@
type SumType = int | string | f64
struct Foo[T] {
field ?SumType
}
fn t[T](val Foo[T]) {
if val.field != none {
if val.field is string {
dump(val.field)
assert val.field == 'foo'
} else if val.field is int {
dump(val.field)
assert val.field == 1
} else if val.field is f64 {
dump(val.field)
assert val.field == 1.23
}
} else {
dump(val.field)
assert val.field == none
}
}
fn test_main() {
t(Foo[int]{})
t(Foo[string]{})
t(Foo[f64]{})
t(Foo[int]{ field: 1 })
t(Foo[string]{ field: 'foo' })
t(Foo[f64]{ field: 1.23 })
}

View File

@ -0,0 +1,46 @@
module main
type Foo = string | int | f32
struct Svc {
mut:
log ?Foo
}
fn t(v string) !string {
return v
}
fn Svc.init(log ?Foo) Svc {
mut svc := Svc{
log: log
}
if svc.log != none {
if svc.log is string {
assert svc.log.str() == 'foo'
_ := t(svc.log) or { panic(err) }
} else {
assert false
}
assert true
}
return svc
}
struct CSvc {
Svc
pub mut:
log ?Foo
}
pub fn CSvc.init(log ?Foo) CSvc {
mut c := CSvc{
log: log
}
c.Svc = Svc.init(log)
return c
}
fn test_main() {
CSvc.init('foo')
}