checker: fix nested if smartcast selector exprs (fix #10372 #10379) (#10502)

pull/10506/head
yuyi 2021-06-18 19:49:15 +08:00 committed by GitHub
parent 05f0f3e180
commit 2298063129
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 16 deletions

View File

@ -1993,9 +1993,9 @@ fn (t Tree) array_node_attr(nodes []ast.Attr) &Node {
return arr 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() mut arr := new_array()
for node in nodes { for _, node in nodes {
arr.add_item(t.scope_struct_field(node)) arr.add_item(t.scope_struct_field(node))
} }
return arr return arr

View File

@ -8,7 +8,7 @@ pub struct Scope {
pub mut: pub mut:
// mut: // mut:
objects map[string]ScopeObject objects map[string]ScopeObject
struct_fields []ScopeStructField struct_fields map[string]ScopeStructField
parent &Scope parent &Scope
detached_from_parent bool detached_from_parent bool
children []&Scope children []&Scope
@ -65,9 +65,10 @@ pub fn (s &Scope) find(name string) ?ScopeObject {
return none 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 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 { if field.struct_type == struct_type && field.name == field_name {
return field 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) { // selector_expr: name.field_name
for f in s.struct_fields { 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 { if f.struct_type == field.struct_type && f.name == field.name {
return return
} }
} }
s.struct_fields << field s.struct_fields[name] = field
} }
pub fn (mut s Scope) register(obj ScopeObject) { pub fn (mut s Scope) register(obj ScopeObject) {
@ -211,7 +213,7 @@ pub fn (sc Scope) show(depth int, max_depth int) string {
else {} 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' out += '$indent * struct_field: $field.struct_type $field.name - $field.typ\n'
} }
if max_depth == 0 || depth < max_depth - 1 { if max_depth == 0 || depth < max_depth - 1 {

View File

@ -442,13 +442,14 @@ pub fn (mut c Checker) interface_decl(mut decl ast.InterfaceDecl) {
iface.pos) iface.pos)
continue 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] { if !efnames_ds_info[f.name] {
efnames_ds_info[f.name] = true efnames_ds_info[f.name] = true
decl_sym.info.fields << f decl_sym.info.fields << f
} }
} }
for m in isym.info.methods { for m in isym_info.methods {
if !emnames_ds_info[m.name] { if !emnames_ds_info[m.name] {
emnames_ds_info[m.name] = true emnames_ds_info[m.name] = true
decl_sym.info.methods << m.new_method_with_receiver_type(decl.typ) 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) field_sym := c.table.get_type_symbol(field.typ)
if field_sym.kind in [.sum_type, .interface_] { if field_sym.kind in [.sum_type, .interface_] {
if !prevent_sum_type_unwrapping_once { 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() 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 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 smartcasts << field.smartcasts
} }
// 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 { if !is_mut || expr.is_mut {
smartcasts << to_type smartcasts << to_type
scope.register_struct_field(ast.ScopeStructField{ scope.register_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

View File

@ -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 { } 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 is_already_sum_type = true
} }
} }
@ -3457,7 +3457,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
if !prevent_sum_type_unwrapping_once { if !prevent_sum_type_unwrapping_once {
// check first if field is sum type because scope searching is expensive // check first if field is sum type because scope searching is expensive
scope := g.file.scope.innermost(node.pos.pos) 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() { if field.orig_type.is_ptr() {
sum_type_dot = '->' sum_type_dot = '->'
} }

View File

@ -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() 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 { && mapping_b.source_position is SourcePosition {
if mapping_a.source_position.source_line != mapping_b.source_position.source_line 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 { || mapping_a.source_position.source_column != mapping_b.source_position.source_column {

View File

@ -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)
}