From 229806312904a4685ab89e6fb1f15826e1b3a04b Mon Sep 17 00:00:00 2001 From: yuyi Date: Fri, 18 Jun 2021 19:49:15 +0800 Subject: [PATCH] checker: fix nested if smartcast selector exprs (fix #10372 #10379) (#10502) --- cmd/tools/vast/vast.v | 4 +-- vlib/v/ast/scope.v | 16 ++++++----- vlib/v/checker/checker.v | 13 +++++---- vlib/v/gen/c/cgen.v | 4 +-- vlib/v/gen/js/sourcemap/mappings.v | 1 + .../if_smartcast_nested_selector_exprs_test.v | 28 +++++++++++++++++++ 6 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 vlib/v/tests/if_smartcast_nested_selector_exprs_test.v diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index ad094dd080..f630fff808 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -1993,9 +1993,9 @@ fn (t Tree) array_node_attr(nodes []ast.Attr) &Node { return arr } -fn (t Tree) array_node_scope_struct_field(nodes []ast.ScopeStructField) &Node { +fn (t Tree) array_node_scope_struct_field(nodes map[string]ast.ScopeStructField) &Node { mut arr := new_array() - for node in nodes { + for _, node in nodes { arr.add_item(t.scope_struct_field(node)) } return arr diff --git a/vlib/v/ast/scope.v b/vlib/v/ast/scope.v index a5fd867bc8..96017c6c94 100644 --- a/vlib/v/ast/scope.v +++ b/vlib/v/ast/scope.v @@ -8,7 +8,7 @@ pub struct Scope { pub mut: // mut: objects map[string]ScopeObject - struct_fields []ScopeStructField + struct_fields map[string]ScopeStructField parent &Scope detached_from_parent bool children []&Scope @@ -65,9 +65,10 @@ pub fn (s &Scope) find(name string) ?ScopeObject { return none } -pub fn (s &Scope) find_struct_field(struct_type Type, field_name string) ?ScopeStructField { +// selector_expr: name.field_name +pub fn (s &Scope) find_struct_field(name string, struct_type Type, field_name string) ?ScopeStructField { for sc := s; true; sc = sc.parent { - for field in sc.struct_fields { + if field := sc.struct_fields[name] { if field.struct_type == struct_type && field.name == field_name { return field } @@ -128,13 +129,14 @@ pub fn (mut s Scope) update_var_type(name string, typ Type) { } } -pub fn (mut s Scope) register_struct_field(field ScopeStructField) { - for f in s.struct_fields { +// selector_expr: name.field_name +pub fn (mut s Scope) register_struct_field(name string, field ScopeStructField) { + if f := s.struct_fields[name] { if f.struct_type == field.struct_type && f.name == field.name { return } } - s.struct_fields << field + s.struct_fields[name] = field } pub fn (mut s Scope) register(obj ScopeObject) { @@ -211,7 +213,7 @@ pub fn (sc Scope) show(depth int, max_depth int) string { else {} } } - for field in sc.struct_fields { + for _, field in sc.struct_fields { out += '$indent * struct_field: $field.struct_type $field.name - $field.typ\n' } if max_depth == 0 || depth < max_depth - 1 { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 4108bc0f58..8900a89215 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -442,13 +442,14 @@ pub fn (mut c Checker) interface_decl(mut decl ast.InterfaceDecl) { iface.pos) continue } - for f in isym.info.fields { + isym_info := isym.info as ast.Interface + for f in isym_info.fields { if !efnames_ds_info[f.name] { efnames_ds_info[f.name] = true decl_sym.info.fields << f } } - for m in isym.info.methods { + for m in isym_info.methods { if !emnames_ds_info[m.name] { emnames_ds_info[m.name] = true decl_sym.info.methods << m.new_method_with_receiver_type(decl.typ) @@ -2983,7 +2984,9 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { field_sym := c.table.get_type_symbol(field.typ) if field_sym.kind in [.sum_type, .interface_] { if !prevent_sum_type_unwrapping_once { - if scope_field := node.scope.find_struct_field(utyp, field_name) { + if scope_field := node.scope.find_struct_field(node.expr.str(), utyp, + field_name) + { return scope_field.smartcasts.last() } } @@ -5764,13 +5767,13 @@ fn (c Checker) smartcast(expr ast.Expr, cur_type ast.Type, to_type_ ast.Type, mu orig_type = field.typ } } - if field := scope.find_struct_field(expr.expr_type, expr.field_name) { + if field := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name) { smartcasts << field.smartcasts } // smartcast either if the value is immutable or if the mut argument is explicitly given if !is_mut || expr.is_mut { smartcasts << to_type - scope.register_struct_field(ast.ScopeStructField{ + scope.register_struct_field(expr.expr.str(), ast.ScopeStructField{ struct_type: expr.expr_type name: expr.field_name typ: cur_type diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 86755255bc..ee8a081cb9 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1842,7 +1842,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ } } } else if expr is ast.SelectorExpr { - if _ := scope.find_struct_field(expr.expr_type, expr.field_name) { + if _ := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name) { is_already_sum_type = true } } @@ -3457,7 +3457,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { if !prevent_sum_type_unwrapping_once { // check first if field is sum type because scope searching is expensive scope := g.file.scope.innermost(node.pos.pos) - if field := scope.find_struct_field(node.expr_type, node.field_name) { + if field := scope.find_struct_field(node.expr.str(), node.expr_type, node.field_name) { if field.orig_type.is_ptr() { sum_type_dot = '->' } diff --git a/vlib/v/gen/js/sourcemap/mappings.v b/vlib/v/gen/js/sourcemap/mappings.v index dfe1318798..7933845d98 100644 --- a/vlib/v/gen/js/sourcemap/mappings.v +++ b/vlib/v/gen/js/sourcemap/mappings.v @@ -149,6 +149,7 @@ fn compare_by_generated_positions_inflated(mapping_a Mapping, mapping_b Mapping) } if mapping_a.source_position.type_name() == mapping_b.source_position.type_name() + && mapping_a.source_position is SourcePosition && mapping_b.source_position is SourcePosition { if mapping_a.source_position.source_line != mapping_b.source_position.source_line || mapping_a.source_position.source_column != mapping_b.source_position.source_column { diff --git a/vlib/v/tests/if_smartcast_nested_selector_exprs_test.v b/vlib/v/tests/if_smartcast_nested_selector_exprs_test.v new file mode 100644 index 0000000000..9c56d6fd03 --- /dev/null +++ b/vlib/v/tests/if_smartcast_nested_selector_exprs_test.v @@ -0,0 +1,28 @@ +struct Empty {} + +type Text = string + +type SumTypeB = Empty | Text + +struct DataStruct { + y SumTypeB +} + +fn isok(a DataStruct, b DataStruct) bool { + if a.y is Text { + if b.y is Text { + return a.y == b.y + } + } + return false +} + +fn test_nested_if_smartcast_selector_exprs() { + a := DataStruct{ + y: Text('da') + } + b := DataStruct{ + y: Text('da') + } + assert isok(a, b) +}