diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 9c990ada5f..11855ff51a 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -91,9 +91,10 @@ pub mut: inside_fn_arg bool // `a`, `b` in `a.f(b)` inside_ct_attr bool // true inside `[if expr]` inside_comptime_for_field bool - 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 - smartcast_mut_pos token.Pos + 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 + smartcast_mut_pos token.Pos // match mut foo, if mut foo is Foo + smartcast_cond_pos token.Pos // match cond ct_cond_stack []ast.Expr mut: stmt_level int // the nesting level inside each stmts list; @@ -1769,6 +1770,10 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { c.note('smartcasting requires either an immutable value, or an explicit mut keyword before the value', c.smartcast_mut_pos) } + if c.smartcast_cond_pos != token.Pos{} { + c.note('smartcast can only be used on the ident or selector, e.g. match foo, match foo.bar', + c.smartcast_cond_pos) + } c.error(unknown_field_msg, node.pos) } return ast.void_type @@ -3357,7 +3362,9 @@ fn (mut c Checker) smartcast(expr_ ast.Expr, cur_type ast.Type, to_type_ ast.Typ c.smartcast_mut_pos = expr.pos } } - else {} + else { + c.smartcast_cond_pos = expr.pos() + } } } diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index 4660ac3287..f50fa265af 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -152,9 +152,8 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { } else { c.stmts(branch.stmts) } - if c.smartcast_mut_pos != token.Pos{} { - c.smartcast_mut_pos = token.Pos{} - } + c.smartcast_mut_pos = token.Pos{} + c.smartcast_cond_pos = token.Pos{} } if expr_required { if branch.stmts.len > 0 && branch.stmts[branch.stmts.len - 1] is ast.ExprStmt { diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index d9f670428c..b3eccd7374 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -43,9 +43,8 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { } else { c.stmts(branch.stmts) } - if c.smartcast_mut_pos != token.Pos{} { - c.smartcast_mut_pos = token.Pos{} - } + c.smartcast_mut_pos = token.Pos{} + c.smartcast_cond_pos = token.Pos{} if node.is_expr { if branch.stmts.len > 0 { // ignore last statement - workaround diff --git a/vlib/v/checker/tests/incorrect_smartcast2_err.out b/vlib/v/checker/tests/incorrect_smartcast2_err.out new file mode 100644 index 0000000000..c3e813e244 --- /dev/null +++ b/vlib/v/checker/tests/incorrect_smartcast2_err.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/incorrect_smartcast2_err.vv:24:9: notice: smartcast can only be used on the ident or selector, e.g. match foo, match foo.bar + 22 | + 23 | fn doesntwork(v []Either) { + 24 | match v[0] { + | ~~~ + 25 | Left { + 26 | println(v[0].error) +vlib/v/checker/tests/incorrect_smartcast2_err.vv:26:17: error: field `error` does not exist or have the same type in all sumtype variants + 24 | match v[0] { + 25 | Left { + 26 | println(v[0].error) + | ~~~~~ + 27 | } + 28 | else {} diff --git a/vlib/v/checker/tests/incorrect_smartcast2_err.vv b/vlib/v/checker/tests/incorrect_smartcast2_err.vv new file mode 100644 index 0000000000..65b4c5b5d3 --- /dev/null +++ b/vlib/v/checker/tests/incorrect_smartcast2_err.vv @@ -0,0 +1,32 @@ +struct Left { + error E +} + +struct Right { + inner T +} + +type Either = + Left | + Right + +fn works(v []Either) { + first := v[0] + match first { + Left { + println(first.error) + } + else {} + } +} + +fn doesntwork(v []Either) { + match v[0] { + Left { + println(v[0].error) + } + else {} + } +} + +fn main() {}