Skip to content

Commit 33e129b

Browse files
authored
parser, checker: only collect/hoist inner vars, when defer is function-scoped (#25693)
1 parent 9760a9c commit 33e129b

File tree

4 files changed

+35
-21
lines changed

4 files changed

+35
-21
lines changed

vlib/v/checker/checker.v

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,24 +2433,24 @@ fn (mut c Checker) defer_stmt(mut node ast.DeferStmt) {
24332433
if c.locked_names.len != 0 || c.rlocked_names.len != 0 {
24342434
c.error('`defer(fn)`s are not allowed in lock statements', node.pos)
24352435
}
2436-
}
2437-
for i, ident in node.defer_vars {
2438-
mut id := ident
2439-
if mut id.info is ast.IdentVar {
2440-
if id.comptime
2441-
&& (id.tok_kind == .question || id.name in ast.valid_comptime_not_user_defined) {
2442-
node.defer_vars[i] = ast.Ident{
2443-
scope: unsafe { nil }
2444-
name: ''
2436+
for i, ident in node.defer_vars {
2437+
mut id := ident
2438+
if mut id.info is ast.IdentVar {
2439+
if id.comptime
2440+
&& (id.tok_kind == .question || id.name in ast.valid_comptime_not_user_defined) {
2441+
node.defer_vars[i] = ast.Ident{
2442+
scope: unsafe { nil }
2443+
name: ''
2444+
}
2445+
continue
24452446
}
2446-
continue
2447-
}
2448-
typ := c.ident(mut id)
2449-
if typ == ast.error_type_idx {
2450-
continue
2447+
typ := c.ident(mut id)
2448+
if typ == ast.error_type_idx {
2449+
continue
2450+
}
2451+
id.info.typ = typ
2452+
node.defer_vars[i] = id
24512453
}
2452-
id.info.typ = typ
2453-
node.defer_vars[i] = id
24542454
}
24552455
}
24562456
c.stmts(mut node.stmts)

vlib/v/parser/assign.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import v.ast
77

88
fn (mut p Parser) assign_stmt() ast.Stmt {
99
mut defer_vars := p.defer_vars.clone()
10-
p.defer_vars = []ast.Ident{}
10+
p.defer_vars = []
1111

1212
exprs := p.expr_list(true)
1313

14-
if !(p.inside_defer && p.tok.kind == .decl_assign) {
14+
if !(p.inside_defer && p.defer_mode == .function && p.tok.kind == .decl_assign) {
1515
defer_vars << p.defer_vars
1616
}
1717
p.defer_vars = defer_vars

vlib/v/parser/parser.v

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ mut:
6363
inside_asm_template bool
6464
inside_asm bool
6565
inside_defer bool
66+
defer_mode ast.DeferMode
6667
inside_generic_params bool // indicates if parsing between `<` and `>` of a method/function
6768
inside_receiver_param bool // indicates if parsing the receiver parameter inside the first `(` and `)` of a method
6869
inside_struct_field_decl bool
@@ -1147,6 +1148,7 @@ fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
11471148
p.check(.rpar)
11481149
}
11491150
p.inside_defer = true
1151+
p.defer_mode = defer_mode
11501152
p.defer_vars = []ast.Ident{}
11511153
stmts := p.parse_block()
11521154
p.inside_defer = false
@@ -1253,10 +1255,9 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
12531255

12541256
left := p.expr_list(p.inside_assign_rhs)
12551257

1256-
if !(p.inside_defer && p.tok.kind == .decl_assign) {
1258+
if !(p.inside_defer && p.defer_mode == .function && p.tok.kind == .decl_assign) {
12571259
defer_vars << p.defer_vars
12581260
}
1259-
12601261
p.defer_vars = defer_vars
12611262

12621263
left0 := left[0]
@@ -3237,7 +3238,7 @@ fn (mut p Parser) show(params ParserShowParams) {
32373238
}
32383239

32393240
fn (mut p Parser) add_defer_var(ident ast.Ident) {
3240-
if p.inside_defer {
3241+
if p.inside_defer && p.defer_mode == .function {
32413242
if !p.defer_vars.any(it.name == ident.name && it.mod == ident.mod)
32423243
&& ident.name !in ['err', 'it'] {
32433244
p.defer_vars << ident

vlib/v/tests/defer/scoped_defer_test.v

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,16 @@ fn test_defer_with_comptime_for() {
117117
}
118118
assert c == 3
119119
}
120+
121+
fn test_defer_fn_with_inner_var() {
122+
mut x := 0
123+
defer {
124+
assert x == 1
125+
}
126+
{
127+
a := 1
128+
defer(fn) {
129+
x = a
130+
}
131+
}
132+
}

0 commit comments

Comments
 (0)