From 27f637a8dcb84709477cfe02f302e4cec57a40ab Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Mon, 20 Jan 2025 12:28:19 -0300 Subject: [PATCH] checker: simplify unwrap nested selector fix (#23526) --- vlib/v/ast/ast.v | 5 +- vlib/v/ast/scope.v | 10 ---- vlib/v/checker/checker.v | 32 ++++--------- .../option_generic_selector_unwrap_test.v | 33 +++++++++++++ .../option_selector_nested_unwrap_test.v | 46 +++++++++++++++++++ 5 files changed, 91 insertions(+), 35 deletions(-) create mode 100644 vlib/v/tests/options/option_generic_selector_unwrap_test.v create mode 100644 vlib/v/tests/options/option_selector_nested_unwrap_test.v diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 67ff7914e4..8936dadd39 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -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) diff --git a/vlib/v/ast/scope.v b/vlib/v/ast/scope.v index 9980befaca..127240c624 100644 --- a/vlib/v/ast/scope.v +++ b/vlib/v/ast/scope.v @@ -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 diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 91fbb36485..532bede4f3 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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 } diff --git a/vlib/v/tests/options/option_generic_selector_unwrap_test.v b/vlib/v/tests/options/option_generic_selector_unwrap_test.v new file mode 100644 index 0000000000..8da51ebf76 --- /dev/null +++ b/vlib/v/tests/options/option_generic_selector_unwrap_test.v @@ -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 }) +} diff --git a/vlib/v/tests/options/option_selector_nested_unwrap_test.v b/vlib/v/tests/options/option_selector_nested_unwrap_test.v new file mode 100644 index 0000000000..466578db3a --- /dev/null +++ b/vlib/v/tests/options/option_selector_nested_unwrap_test.v @@ -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') +}