1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

parser: check undefined ident in if guard expr (#15253)

This commit is contained in:
yuyi 2022-07-29 00:13:41 +08:00 committed by GitHub
parent 242ade8938
commit 17ce1a0e8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 118 additions and 1 deletions

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/undefined_ident_in_if_guard_err.vv:6:11: error: undefined variable: `re`
4 |
5 | fn main() {
6 | if re := re.regex_opt('a') {
| ~~
7 | print('Hooray')
8 | }

View File

@ -0,0 +1,9 @@
module main
import regex
fn main() {
if re := re.regex_opt('a') {
print('Hooray')
}
}

View File

@ -118,6 +118,102 @@ fn (mut p Parser) check_undefined_variables(exprs []ast.Expr, val ast.Expr) ? {
}
}
fn (mut p Parser) check_undefined_variables_by_names(names []string, val ast.Expr) ? {
p.expr_level++
defer {
p.expr_level--
}
if p.expr_level > parser.max_expr_level {
return error('expr level > $parser.max_expr_level')
}
match val {
ast.Ident {
for name in names {
if name == val.name && val.kind != .blank_ident {
p.error_with_pos('undefined variable: `$val.name`', val.pos)
return error('undefined variable: `$val.name`')
}
}
}
ast.ArrayInit {
if val.has_cap {
p.check_undefined_variables_by_names(names, val.cap_expr)?
}
if val.has_len {
p.check_undefined_variables_by_names(names, val.len_expr)?
}
if val.has_default {
p.check_undefined_variables_by_names(names, val.default_expr)?
}
for expr in val.exprs {
p.check_undefined_variables_by_names(names, expr)?
}
}
ast.CallExpr {
p.check_undefined_variables_by_names(names, val.left)?
for arg in val.args {
p.check_undefined_variables_by_names(names, arg.expr)?
}
}
ast.InfixExpr {
p.check_undefined_variables_by_names(names, val.left)?
p.check_undefined_variables_by_names(names, val.right)?
}
ast.IfExpr {
p.check_undefined_variables_by_names(names, val.left)?
for branch in val.branches {
p.check_undefined_variables_by_names(names, branch.cond)?
for stmt in branch.stmts {
if stmt is ast.ExprStmt {
p.check_undefined_variables_by_names(names, stmt.expr)?
}
}
}
}
ast.MapInit {
for key in val.keys {
p.check_undefined_variables_by_names(names, key)?
}
for value in val.vals {
p.check_undefined_variables_by_names(names, value)?
}
}
ast.MatchExpr {
p.check_undefined_variables_by_names(names, val.cond)?
for branch in val.branches {
for expr in branch.exprs {
p.check_undefined_variables_by_names(names, expr)?
}
for stmt in branch.stmts {
if stmt is ast.ExprStmt {
p.check_undefined_variables_by_names(names, stmt.expr)?
}
}
}
}
ast.ParExpr {
p.check_undefined_variables_by_names(names, val.expr)?
}
ast.PostfixExpr {
p.check_undefined_variables_by_names(names, val.expr)?
}
ast.PrefixExpr {
p.check_undefined_variables_by_names(names, val.right)?
}
ast.StringInterLiteral {
for expr_ in val.exprs {
p.check_undefined_variables_by_names(names, expr_)?
}
}
ast.StructInit {
for field in val.fields {
p.check_undefined_variables_by_names(names, field.expr)?
}
}
else {}
}
}
fn (mut p Parser) check_cross_variables(exprs []ast.Expr, val ast.Expr) bool {
val_str := val.str()
match val {

View File

@ -87,6 +87,7 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
p.open_scope()
is_guard = true
mut vars := []ast.IfGuardVar{}
mut var_names := []string{}
for {
mut var := ast.IfGuardVar{}
mut is_mut := false
@ -97,6 +98,7 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
var.is_mut = is_mut
var.pos = p.tok.pos()
var.name = p.check_name()
var_names << var.name
if p.scope.known_var(var.name) {
p.error_with_pos('redefinition of `$var.name`', var.pos)
@ -115,7 +117,10 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
p.error_with_pos('if guard condition expression is illegal, it should return optional',
expr.pos())
}
p.check_undefined_variables_by_names(var_names, expr) or {
p.error_with_pos(err.msg(), pos)
break
}
cond = ast.IfGuardExpr{
vars: vars
expr: expr