v.checker: fix spurious warning for `if x := map_of_sumtypes[k] {}`

pull/11510/head
Delyan Angelov 2021-09-15 15:42:28 +03:00
parent 7145461cc5
commit 5bc6cc9512
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
4 changed files with 55 additions and 18 deletions

View File

@ -73,14 +73,14 @@ pub mut:
returns bool returns bool
scope_returns bool scope_returns bool
mod string // current module name mod string // current module name
is_builtin_mod bool // are we in `builtin`? is_builtin_mod bool // true inside the 'builtin', 'os' or 'strconv' modules; TODO: remove the need for special casing this
inside_unsafe bool inside_unsafe bool // true inside `unsafe {}` blocks
inside_const bool inside_const bool // true inside `const ( ... )` blocks
inside_anon_fn bool inside_anon_fn bool // true inside `fn() { ... }()`
inside_ref_lit bool inside_ref_lit bool // true inside `a := &something`
inside_defer bool inside_defer bool // true inside `defer {}` blocks
inside_fn_arg bool // `a`, `b` in `a.f(b)` inside_fn_arg bool // `a`, `b` in `a.f(b)`
inside_ct_attr bool // true inside [if expr] inside_ct_attr bool // true inside `[if expr]`
skip_flags bool // should `#flag` and `#include` be skipped skip_flags bool // should `#flag` and `#include` be skipped
fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc
ct_cond_stack []ast.Expr ct_cond_stack []ast.Expr
@ -104,6 +104,7 @@ mut:
inside_selector_expr bool inside_selector_expr bool
inside_println_arg bool inside_println_arg bool
inside_decl_rhs bool inside_decl_rhs bool
inside_if_guard bool // true inside the guard condition of `if x := opt() {}`
need_recheck_generic_fns bool // need recheck generic fns because there are cascaded nested generic fn need_recheck_generic_fns bool // need recheck generic fns because there are cascaded nested generic fn
} }
@ -5480,7 +5481,10 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type {
return c.if_expr(mut node) return c.if_expr(mut node)
} }
ast.IfGuardExpr { ast.IfGuardExpr {
old_inside_if_guard := c.inside_if_guard
c.inside_if_guard = true
node.expr_type = c.expr(node.expr) node.expr_type = c.expr(node.expr)
c.inside_if_guard = old_inside_if_guard
if !node.expr_type.has_flag(.optional) { if !node.expr_type.has_flag(.optional) {
mut no_opt := true mut no_opt := true
match mut node.expr { match mut node.expr {
@ -5997,8 +6001,7 @@ pub fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
if mut obj.expr is ast.IfGuardExpr { if mut obj.expr is ast.IfGuardExpr {
// new variable from if guard shouldn't have the optional flag for further use // new variable from if guard shouldn't have the optional flag for further use
// a temp variable will be generated which unwraps it // a temp variable will be generated which unwraps it
if_guard_var_type := c.expr(obj.expr.expr) typ = obj.expr.expr_type.clear_flag(.optional)
typ = if_guard_var_type.clear_flag(.optional)
} else { } else {
typ = c.expr(obj.expr) typ = c.expr(obj.expr)
} }
@ -7462,7 +7465,7 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type {
} }
value_sym := c.table.get_type_symbol(info.value_type) value_sym := c.table.get_type_symbol(info.value_type)
if !node.is_setter && value_sym.kind == .sum_type && node.or_expr.kind == .absent if !node.is_setter && value_sym.kind == .sum_type && node.or_expr.kind == .absent
&& !c.inside_unsafe { && !c.inside_unsafe && !c.inside_if_guard {
c.warn('`or {}` block required when indexing a map with sum type value', c.warn('`or {}` block required when indexing a map with sum type value',
node.pos) node.pos)
} }

View File

@ -1,6 +1,6 @@
vlib/v/checker/tests/require_or_block_sumtype_map.err.vv:5:8: error: `or {}` block required when indexing a map with sum type value vlib/v/checker/tests/require_or_block_sumtype_map.err.vv:8:8: error: `or {}` block required when indexing a map with sum type value
3 | fn main() { 6 | println(y)
4 | x := map[string]Abc{} 7 | }
5 | _ := x['nonexisting'] 8 | _ := x['nonexisting']
| ~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~
6 | } 9 | }

View File

@ -2,5 +2,8 @@ type Abc = string | int
fn main() { fn main() {
x := map[string]Abc{} x := map[string]Abc{}
if y := x['nonexisting'] {
println(y)
}
_ := x['nonexisting'] _ := x['nonexisting']
} }

View File

@ -0,0 +1,31 @@
// NB: this test should be able to run without warnings/errors
type SumType = bool | int | string
fn test_reading_from_a_map_of_sumtype_values() {
mut values := map[string]SumType{}
values['abc'] = 'xyz'
values['xyz'] = 123
values['xxx'] = true
println(unsafe { values['abcz'] }) // no warning/error, due to the unsafe{}
if value := values['abc'] {
eprintln('existing key `abc` is present, value: $value')
assert true
}
if (values['abc'] or { 'zzzz' }) is string {
eprintln('existing key `abc` is present, value is a string')
assert true
}
if (values['abc'] or { 123 }) is int {
eprintln('the existing keyed value is an int')
assert false
}
if (values['something else'] or { 'zzzz' }) is string {
eprintln('default value for non existing key is a string')
assert true
}
if (values['something else'] or { 123 }) is int {
eprintln('default value for non existing key is an int')
assert true
}
}