mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: disallow most statements in if/match expression branches (#6509)
This commit is contained in:
parent
3a8be4d8d9
commit
18be7b115a
@ -34,6 +34,7 @@ pub struct Block {
|
||||
pub:
|
||||
stmts []Stmt
|
||||
is_unsafe bool
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
// | IncDecStmt k
|
||||
@ -1097,6 +1098,19 @@ pub fn (expr Expr) is_expr() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// check if stmt can be an expression in C
|
||||
pub fn (stmt Stmt) check_c_expr()? {
|
||||
match stmt {
|
||||
AssignStmt {return}
|
||||
ExprStmt {
|
||||
if stmt.expr.is_expr() {return}
|
||||
return error('unsupported statement (`${typeof(stmt.expr)}`)')
|
||||
}
|
||||
else {}
|
||||
}
|
||||
return error('unsupported statement (`${typeof(stmt)}`)')
|
||||
}
|
||||
|
||||
pub fn (stmt Stmt) position() token.Position {
|
||||
match stmt {
|
||||
AssertStmt { return stmt.pos }
|
||||
@ -1104,8 +1118,9 @@ pub fn (stmt Stmt) position() token.Position {
|
||||
/*
|
||||
// Attr {
|
||||
// }
|
||||
// Block {
|
||||
// }
|
||||
*/
|
||||
Block { return stmt.pos }
|
||||
/*
|
||||
// BranchStmt {
|
||||
// }
|
||||
*/
|
||||
|
@ -3002,6 +3002,13 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
|
||||
mut branch_without_return := false
|
||||
for branch in node.branches {
|
||||
c.stmts(branch.stmts)
|
||||
if node.is_expr {
|
||||
for st in branch.stmts {
|
||||
st.check_c_expr() or {
|
||||
c.error('`match` expression branch has $err', st.position())
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the last statement is an expression, return its type
|
||||
if branch.stmts.len > 0 {
|
||||
match mut branch.stmts[branch.stmts.len - 1] as stmt {
|
||||
@ -3404,6 +3411,11 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||
c.error('`$if_kind` expression requires an expression as the last statement of every branch',
|
||||
branch.pos)
|
||||
}
|
||||
for st in branch.stmts {
|
||||
st.check_c_expr() or {
|
||||
c.error('`if` expression branch has $err', st.position())
|
||||
}
|
||||
}
|
||||
}
|
||||
// Also check for returns inside a comp.if's statements, even if its contents aren't parsed
|
||||
if has_return := c.has_return(branch.stmts) {
|
||||
|
28
vlib/v/checker/tests/if_match_expr.out
Normal file
28
vlib/v/checker/tests/if_match_expr.out
Normal file
@ -0,0 +1,28 @@
|
||||
vlib/v/checker/tests/if_match_expr.vv:8:6: error: `if` expression branch has unsupported statement (`v.ast.ForStmt`)
|
||||
6 | if true {1} else {-1} // OK
|
||||
7 | } else {
|
||||
8 | for {break}
|
||||
| ^
|
||||
9 | {}
|
||||
10 | -1
|
||||
vlib/v/checker/tests/if_match_expr.vv:9:2: error: `if` expression branch has unsupported statement (`v.ast.Block`)
|
||||
7 | } else {
|
||||
8 | for {break}
|
||||
9 | {}
|
||||
| ^
|
||||
10 | -1
|
||||
11 | }
|
||||
vlib/v/checker/tests/if_match_expr.vv:15:10: error: `match` expression branch has unsupported statement (`v.ast.AssertStmt`)
|
||||
13 | _ = match true {
|
||||
14 | true {
|
||||
15 | assert true
|
||||
| ~~~~
|
||||
16 | 1
|
||||
17 | }
|
||||
vlib/v/checker/tests/if_match_expr.vv:19:3: error: `match` expression branch has unsupported statement (`v.ast.IfExpr`)
|
||||
17 | }
|
||||
18 | else {
|
||||
19 | if true {} // statement not expression
|
||||
| ~~
|
||||
20 | (-1) // parens needed ATM due to bug
|
||||
21 | }
|
22
vlib/v/checker/tests/if_match_expr.vv
Normal file
22
vlib/v/checker/tests/if_match_expr.vv
Normal file
@ -0,0 +1,22 @@
|
||||
// only C expressions are allowed for each statement
|
||||
|
||||
_ = if true {
|
||||
if true {} // FIXME should error, if statement
|
||||
_ = if true {1} else {-1} // OK
|
||||
if true {1} else {-1} // OK
|
||||
} else {
|
||||
for {break}
|
||||
{}
|
||||
-1
|
||||
}
|
||||
|
||||
_ = match true {
|
||||
true {
|
||||
assert true
|
||||
1
|
||||
}
|
||||
else {
|
||||
if true {} // statement not expression
|
||||
(-1) // parens needed ATM due to bug
|
||||
}
|
||||
}
|
@ -557,9 +557,11 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
||||
p.is_stmt_ident = p.tok.kind == .name
|
||||
match p.tok.kind {
|
||||
.lcbr {
|
||||
pos := p.tok.position()
|
||||
stmts := p.parse_block()
|
||||
return ast.Block{
|
||||
stmts: stmts
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
.key_assert {
|
||||
@ -1989,6 +1991,7 @@ fn (mut p Parser) unsafe_stmt() ast.Stmt {
|
||||
p.next()
|
||||
return ast.Block{
|
||||
is_unsafe: true
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
p.inside_unsafe = true
|
||||
@ -2025,5 +2028,6 @@ fn (mut p Parser) unsafe_stmt() ast.Stmt {
|
||||
return ast.Block{
|
||||
stmts: stmts
|
||||
is_unsafe: true
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user