Skip to content

Commit 0bb587c

Browse files
checker: fix defer ident handling & fix defer optional error message (#10975)
1 parent a7c2aaf commit 0bb587c

File tree

5 files changed

+37
-3
lines changed

5 files changed

+37
-3
lines changed

vlib/v/checker/checker.v

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3208,8 +3208,13 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type ast.Type) ast
32083208
if expr is ast.CallExpr {
32093209
if expr.return_type.has_flag(.optional) {
32103210
if expr.or_block.kind == .absent {
3211-
c.error('${expr.name}() returns an option, so it should have either an `or {}` block, or `?` at the end',
3212-
expr.pos)
3211+
if c.inside_defer {
3212+
c.error('${expr.name}() returns an option, so it should have an `or {}` block at the end',
3213+
expr.pos)
3214+
} else {
3215+
c.error('${expr.name}() returns an option, so it should have either an `or {}` block, or `?` at the end',
3216+
expr.pos)
3217+
}
32133218
} else {
32143219
c.check_or_expr(expr.or_block, ret_type, expr.return_type.clear_flag(.optional))
32153220
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
vlib/v/checker/tests/defer_optional.vv:5:3: error: opt() returns an option, so it should have an `or {}` block at the end
2+
3 | fn thing() ?string {
3+
4 | defer {
4+
5 | opt()
5+
| ~~~~~
6+
6 | }
7+
7 | return 'ok'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn opt() ? {}
2+
3+
fn thing() ?string {
4+
defer {
5+
opt()
6+
}
7+
return 'ok'
8+
}

vlib/v/gen/c/cgen.v

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4902,7 +4902,9 @@ fn (mut g Gen) return_stmt(node ast.Return) {
49024902
// `tmp := foo(a, b, c); free(a); free(b); free(c); return tmp;`
49034903
// Save return value in a temp var so that all args (a,b,c) can be freed
49044904
// Don't use a tmp var if a variable is simply returned: `return x`
4905-
if node.exprs[0] !is ast.Ident {
4905+
// Just in case of defer statements exists, that the return values cannot
4906+
// be modified.
4907+
if node.exprs[0] !is ast.Ident || use_tmp_var {
49064908
g.write('$ret_typ $tmpvar = ')
49074909
} else {
49084910
use_tmp_var = false

vlib/v/tests/defer_test.v

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,15 @@ fn test_defer_str_interpol() {
142142
t << '${t[0]}'
143143
}
144144
}
145+
146+
fn test_defer_not_change_return_values() {
147+
assert num() == 10
148+
}
149+
150+
fn num() int {
151+
mut ret := 10
152+
defer {
153+
ret = 20
154+
}
155+
return ret
156+
}

0 commit comments

Comments
 (0)