Skip to content

Commit

Permalink
checker: simplify unwrap nested selector fix (#23526)
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp authored Jan 20, 2025
1 parent facee32 commit 27f637a
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 35 deletions.
5 changes: 2 additions & 3 deletions vlib/v/ast/ast.v
Original file line number Diff line number Diff line change
Expand Up @@ -925,9 +925,8 @@ pub:
name string
pos token.Pos
typ Type
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
orig_type Type // original sumtype type; 0 if it's not a sumtype
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
// 10 <- original type (orig_type)
// [11, 12, 13] <- cast order (smartcasts)
Expand Down
10 changes: 0 additions & 10 deletions vlib/v/ast/scope.v
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,6 @@ pub fn (mut s Scope) register_struct_field(name string, field ScopeStructField)
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) {
if !(obj.name == '_' || obj.name in s.objects) {
s.objects[obj.name] = obj
Expand Down
32 changes: 10 additions & 22 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -4286,33 +4286,21 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
orig_type = field.typ
}
}
mut nested_unwrap := false
if mut field := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name) {
expr_str := expr.expr.str()
if mut field := scope.find_struct_field(expr_str, expr.expr_type, expr.field_name) {
smartcasts << field.smartcasts
nested_unwrap = smartcasts.len > 1
}
// 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) {
smartcasts << to_type
if nested_unwrap {
scope.register_or_update_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 {
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
})
}
scope.register_struct_field(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 {
c.smartcast_mut_pos = expr.pos
}
Expand Down
33 changes: 33 additions & 0 deletions vlib/v/tests/options/option_generic_selector_unwrap_test.v
Original file line number Diff line number Diff line change
@@ -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 })
}
46 changes: 46 additions & 0 deletions vlib/v/tests/options/option_selector_nested_unwrap_test.v
Original file line number Diff line number Diff line change
@@ -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')
}

0 comments on commit 27f637a

Please sign in to comment.