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

View File

@ -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 {

View File

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

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 {
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 = '->'
}

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()
&& 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 {

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