checker: handle invalid smartcast with if/match none ident or selector (fix #12317) (#13762)

pull/13776/head
yuyi 2022-03-18 22:50:54 +08:00 committed by GitHub
parent f903ef24e8
commit 5f79fa8a30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 10 deletions

View File

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

View File

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

View File

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

View File

@ -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<int, int>) {
24 | match v[0] {
| ~~~
25 | Left<int> {
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<int> {
26 | println(v[0].error)
| ~~~~~
27 | }
28 | else {}

View File

@ -0,0 +1,32 @@
struct Left<E> {
error E
}
struct Right<T> {
inner T
}
type Either<T, E> =
Left<E> |
Right<T>
fn works(v []Either<int, int>) {
first := v[0]
match first {
Left<int> {
println(first.error)
}
else {}
}
}
fn doesntwork(v []Either<int, int>) {
match v[0] {
Left<int> {
println(v[0].error)
}
else {}
}
}
fn main() {}