all: allow defer use from other scope (#10284)
parent
eac1e25c5d
commit
38796521fa
|
@ -629,6 +629,7 @@ pub:
|
||||||
tok_kind token.Kind
|
tok_kind token.Kind
|
||||||
pos token.Position
|
pos token.Position
|
||||||
mut_pos token.Position
|
mut_pos token.Position
|
||||||
|
comptime bool
|
||||||
pub mut:
|
pub mut:
|
||||||
scope &Scope
|
scope &Scope
|
||||||
obj ScopeObject
|
obj ScopeObject
|
||||||
|
@ -983,6 +984,7 @@ pub:
|
||||||
stmts []Stmt
|
stmts []Stmt
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
|
defer_vars []Ident
|
||||||
ifdef string
|
ifdef string
|
||||||
idx_in_fn int = -1 // index in FnDecl.defer_stmts
|
idx_in_fn int = -1 // index in FnDecl.defer_stmts
|
||||||
}
|
}
|
||||||
|
|
|
@ -3955,6 +3955,29 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
||||||
if c.locked_names.len != 0 || c.rlocked_names.len != 0 {
|
if c.locked_names.len != 0 || c.rlocked_names.len != 0 {
|
||||||
c.error('defers are not allowed in lock statements', node.pos)
|
c.error('defers are not allowed in lock statements', node.pos)
|
||||||
}
|
}
|
||||||
|
for i, ident in node.defer_vars {
|
||||||
|
mut id := ident
|
||||||
|
if id.info is ast.IdentVar {
|
||||||
|
if id.comptime && (id.name in checker.valid_comp_if_compilers
|
||||||
|
|| id.name in checker.valid_comp_if_os
|
||||||
|
|| id.name in checker.valid_comp_if_other
|
||||||
|
|| id.name in checker.valid_comp_if_platforms) {
|
||||||
|
node.defer_vars[i] = ast.Ident{
|
||||||
|
scope: 0
|
||||||
|
name: ''
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mut info := id.info as ast.IdentVar
|
||||||
|
typ := c.ident(mut id)
|
||||||
|
if typ == ast.error_type_idx {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
info.typ = typ
|
||||||
|
id.info = info
|
||||||
|
node.defer_vars[i] = id
|
||||||
|
}
|
||||||
|
}
|
||||||
c.stmts(node.stmts)
|
c.stmts(node.stmts)
|
||||||
}
|
}
|
||||||
ast.EnumDecl {
|
ast.EnumDecl {
|
||||||
|
|
|
@ -174,6 +174,8 @@ mut:
|
||||||
obf_table map[string]string
|
obf_table map[string]string
|
||||||
// main_fn_decl_node ast.FnDecl
|
// main_fn_decl_node ast.FnDecl
|
||||||
expected_cast_type ast.Type // for match expr of sumtypes
|
expected_cast_type ast.Type // for match expr of sumtypes
|
||||||
|
defer_vars []string
|
||||||
|
anon_fn bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
||||||
|
@ -2248,7 +2250,11 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
for i, lx in assign_stmt.left {
|
for i, lx in assign_stmt.left {
|
||||||
mut is_auto_heap := false
|
mut is_auto_heap := false
|
||||||
|
mut ident := ast.Ident{
|
||||||
|
scope: 0
|
||||||
|
}
|
||||||
if lx is ast.Ident {
|
if lx is ast.Ident {
|
||||||
|
ident = lx
|
||||||
if lx.kind == .blank_ident {
|
if lx.kind == .blank_ident {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -2256,7 +2262,11 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
is_auto_heap = lx.obj.is_auto_heap
|
is_auto_heap = lx.obj.is_auto_heap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
styp := g.typ(assign_stmt.left_types[i])
|
styp := if ident.name in g.defer_vars {
|
||||||
|
''
|
||||||
|
} else {
|
||||||
|
g.typ(assign_stmt.left_types[i])
|
||||||
|
}
|
||||||
if assign_stmt.op == .decl_assign {
|
if assign_stmt.op == .decl_assign {
|
||||||
g.write('$styp ')
|
g.write('$styp ')
|
||||||
if is_auto_heap {
|
if is_auto_heap {
|
||||||
|
@ -2403,7 +2413,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
is_auto_heap = left.obj.is_auto_heap
|
is_auto_heap = left.obj.is_auto_heap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
styp := g.typ(var_type)
|
styp := if ident.name in g.defer_vars { '' } else { g.typ(var_type) }
|
||||||
mut is_fixed_array_init := false
|
mut is_fixed_array_init := false
|
||||||
mut has_val := false
|
mut has_val := false
|
||||||
match val {
|
match val {
|
||||||
|
@ -2946,7 +2956,9 @@ fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) {
|
||||||
fn (mut g Gen) gen_anon_fn_decl(mut node ast.AnonFn) {
|
fn (mut g Gen) gen_anon_fn_decl(mut node ast.AnonFn) {
|
||||||
if !node.has_gen {
|
if !node.has_gen {
|
||||||
pos := g.out.len
|
pos := g.out.len
|
||||||
|
g.anon_fn = true
|
||||||
g.stmt(node.decl)
|
g.stmt(node.decl)
|
||||||
|
g.anon_fn = false
|
||||||
fn_body := g.out.after(pos)
|
fn_body := g.out.after(pos)
|
||||||
g.out.go_back(fn_body.len)
|
g.out.go_back(fn_body.len)
|
||||||
g.anon_fn_definitions << fn_body
|
g.anon_fn_definitions << fn_body
|
||||||
|
|
|
@ -103,6 +103,18 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
||||||
// || node.no_body {
|
// || node.no_body {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmp_defer_vars := g.defer_vars // must be here because of workflow
|
||||||
|
if !g.anon_fn {
|
||||||
|
g.defer_vars = []string{}
|
||||||
|
} else {
|
||||||
|
if node.defer_stmts.len > 0 {
|
||||||
|
g.defer_vars = []string{}
|
||||||
|
defer {
|
||||||
|
g.defer_vars = tmp_defer_vars
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Skip [if xxx] if xxx is not defined
|
// Skip [if xxx] if xxx is not defined
|
||||||
/*
|
/*
|
||||||
for attr in node.attrs {
|
for attr in node.attrs {
|
||||||
|
@ -265,6 +277,18 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
for defer_stmt in node.defer_stmts {
|
for defer_stmt in node.defer_stmts {
|
||||||
g.writeln('bool ${g.defer_flag_var(defer_stmt)} = false;')
|
g.writeln('bool ${g.defer_flag_var(defer_stmt)} = false;')
|
||||||
|
for var in defer_stmt.defer_vars {
|
||||||
|
if var.name in fargs || var.kind == .constant {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if var.info is ast.IdentVar {
|
||||||
|
info := var.info
|
||||||
|
if var.name !in g.defer_vars {
|
||||||
|
g.defer_vars << var.name
|
||||||
|
g.writeln('${g.typ(info.typ)} $var.name;')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if is_live_wrap {
|
if is_live_wrap {
|
||||||
// The live function just calls its implementation dual, while ensuring
|
// The live function just calls its implementation dual, while ensuring
|
||||||
|
|
|
@ -6,7 +6,15 @@ module parser
|
||||||
import v.ast
|
import v.ast
|
||||||
|
|
||||||
fn (mut p Parser) assign_stmt() ast.Stmt {
|
fn (mut p Parser) assign_stmt() ast.Stmt {
|
||||||
|
mut defer_vars := p.defer_vars
|
||||||
|
p.defer_vars = []ast.Ident{}
|
||||||
|
|
||||||
exprs, comments := p.expr_list()
|
exprs, comments := p.expr_list()
|
||||||
|
|
||||||
|
if !(p.inside_defer && p.tok.kind == .decl_assign) {
|
||||||
|
defer_vars << p.defer_vars
|
||||||
|
}
|
||||||
|
p.defer_vars = defer_vars
|
||||||
return p.partial_assign_stmt(exprs, comments)
|
return p.partial_assign_stmt(exprs, comments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,9 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
|
||||||
prev_guard = true
|
prev_guard = true
|
||||||
} else {
|
} else {
|
||||||
prev_guard = false
|
prev_guard = false
|
||||||
|
p.comp_if_cond = true
|
||||||
cond = p.expr(0)
|
cond = p.expr(0)
|
||||||
|
p.comp_if_cond = false
|
||||||
}
|
}
|
||||||
comments << p.eat_comments({})
|
comments << p.eat_comments({})
|
||||||
end_pos := p.prev_tok.position()
|
end_pos := p.prev_tok.position()
|
||||||
|
|
|
@ -77,6 +77,9 @@ mut:
|
||||||
inside_asm_template bool
|
inside_asm_template bool
|
||||||
inside_asm bool
|
inside_asm bool
|
||||||
global_labels []string
|
global_labels []string
|
||||||
|
inside_defer bool
|
||||||
|
comp_if_cond bool
|
||||||
|
defer_vars []ast.Ident
|
||||||
}
|
}
|
||||||
|
|
||||||
// for tests
|
// for tests
|
||||||
|
@ -792,9 +795,13 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
||||||
.key_defer {
|
.key_defer {
|
||||||
p.next()
|
p.next()
|
||||||
spos := p.tok.position()
|
spos := p.tok.position()
|
||||||
|
p.inside_defer = true
|
||||||
|
p.defer_vars = []ast.Ident{}
|
||||||
stmts := p.parse_block()
|
stmts := p.parse_block()
|
||||||
|
p.inside_defer = false
|
||||||
return ast.DeferStmt{
|
return ast.DeferStmt{
|
||||||
stmts: stmts
|
stmts: stmts
|
||||||
|
defer_vars: p.defer_vars.clone()
|
||||||
pos: spos.extend_with_last_line(p.tok.position(), p.prev_tok.line_nr)
|
pos: spos.extend_with_last_line(p.tok.position(), p.prev_tok.line_nr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1689,7 +1696,18 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
|
||||||
// collect things upto hard boundaries
|
// collect things upto hard boundaries
|
||||||
tok := p.tok
|
tok := p.tok
|
||||||
mut pos := tok.position()
|
mut pos := tok.position()
|
||||||
|
|
||||||
|
mut defer_vars := p.defer_vars
|
||||||
|
p.defer_vars = []ast.Ident{}
|
||||||
|
|
||||||
left, left_comments := p.expr_list()
|
left, left_comments := p.expr_list()
|
||||||
|
|
||||||
|
if !(p.inside_defer && p.tok.kind == .decl_assign) {
|
||||||
|
defer_vars << p.defer_vars
|
||||||
|
}
|
||||||
|
|
||||||
|
p.defer_vars = defer_vars
|
||||||
|
|
||||||
left0 := left[0]
|
left0 := left[0]
|
||||||
if tok.kind == .key_mut && p.tok.kind != .decl_assign {
|
if tok.kind == .key_mut && p.tok.kind != .decl_assign {
|
||||||
return p.error('expecting `:=` (e.g. `mut x :=`)')
|
return p.error('expecting `:=` (e.g. `mut x :=`)')
|
||||||
|
@ -1750,6 +1768,7 @@ pub fn (mut p Parser) parse_ident(language ast.Language) ast.Ident {
|
||||||
return ast.Ident{
|
return ast.Ident{
|
||||||
tok_kind: p.tok.kind
|
tok_kind: p.tok.kind
|
||||||
name: '_'
|
name: '_'
|
||||||
|
comptime: p.comp_if_cond
|
||||||
kind: .blank_ident
|
kind: .blank_ident
|
||||||
pos: pos
|
pos: pos
|
||||||
info: ast.IdentVar{
|
info: ast.IdentVar{
|
||||||
|
@ -1769,6 +1788,7 @@ pub fn (mut p Parser) parse_ident(language ast.Language) ast.Ident {
|
||||||
tok_kind: p.tok.kind
|
tok_kind: p.tok.kind
|
||||||
kind: .unresolved
|
kind: .unresolved
|
||||||
name: name
|
name: name
|
||||||
|
comptime: p.comp_if_cond
|
||||||
language: language
|
language: language
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
pos: pos
|
pos: pos
|
||||||
|
@ -1954,7 +1974,14 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
||||||
} else if p.peek_tok.kind == .dot && p.peek_token(2).kind != .eof
|
} else if p.peek_tok.kind == .dot && p.peek_token(2).kind != .eof
|
||||||
&& p.peek_token(2).lit.len == 0 {
|
&& p.peek_token(2).lit.len == 0 {
|
||||||
// incomplete module selector must be handled by dot_expr instead
|
// incomplete module selector must be handled by dot_expr instead
|
||||||
node = p.parse_ident(language)
|
ident := p.parse_ident(language)
|
||||||
|
node = ident
|
||||||
|
if p.inside_defer {
|
||||||
|
if p.defer_vars.filter(it.name == ident.name
|
||||||
|
&& it.mod == ident.mod).len == 0 && ident.name != 'err' {
|
||||||
|
p.defer_vars << ident
|
||||||
|
}
|
||||||
|
}
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1975,7 +2002,14 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
||||||
same_line := p.tok.line_nr == p.peek_tok.line_nr
|
same_line := p.tok.line_nr == p.peek_tok.line_nr
|
||||||
// `(` must be on same line as name token otherwise it's a ParExpr
|
// `(` must be on same line as name token otherwise it's a ParExpr
|
||||||
if !same_line && p.peek_tok.kind == .lpar {
|
if !same_line && p.peek_tok.kind == .lpar {
|
||||||
node = p.parse_ident(language)
|
ident := p.parse_ident(language)
|
||||||
|
node = ident
|
||||||
|
if p.inside_defer {
|
||||||
|
if p.defer_vars.filter(it.name == ident.name && it.mod == ident.mod).len == 0
|
||||||
|
&& ident.name != 'err' {
|
||||||
|
p.defer_vars << ident
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if p.peek_tok.kind == .lpar
|
} else if p.peek_tok.kind == .lpar
|
||||||
|| (is_optional && p.peek_token(2).kind == .lpar) || p.is_generic_call() {
|
|| (is_optional && p.peek_token(2).kind == .lpar) || p.is_generic_call() {
|
||||||
// foo(), foo<int>() or type() cast
|
// foo(), foo<int>() or type() cast
|
||||||
|
@ -2087,7 +2121,14 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
||||||
// JS. function call with more than 1 dot
|
// JS. function call with more than 1 dot
|
||||||
node = p.call_expr(language, mod)
|
node = p.call_expr(language, mod)
|
||||||
} else {
|
} else {
|
||||||
node = p.parse_ident(language)
|
ident := p.parse_ident(language)
|
||||||
|
node = ident
|
||||||
|
if p.inside_defer {
|
||||||
|
if p.defer_vars.filter(it.name == ident.name && it.mod == ident.mod).len == 0
|
||||||
|
&& ident.name != 'err' {
|
||||||
|
p.defer_vars << ident
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.expr_mod = ''
|
p.expr_mod = ''
|
||||||
return node
|
return node
|
||||||
|
|
|
@ -33,7 +33,14 @@ pub fn (mut p Parser) check_expr(precedence int) ?ast.Expr {
|
||||||
// Prefix
|
// Prefix
|
||||||
match p.tok.kind {
|
match p.tok.kind {
|
||||||
.key_mut, .key_shared, .key_atomic, .key_static {
|
.key_mut, .key_shared, .key_atomic, .key_static {
|
||||||
node = p.parse_ident(ast.Language.v)
|
ident := p.parse_ident(ast.Language.v)
|
||||||
|
node = ident
|
||||||
|
if p.inside_defer {
|
||||||
|
if p.defer_vars.filter(it.name == ident.name && it.mod == ident.mod).len == 0
|
||||||
|
&& ident.name != 'err' {
|
||||||
|
p.defer_vars << ident
|
||||||
|
}
|
||||||
|
}
|
||||||
p.is_stmt_ident = is_stmt_ident
|
p.is_stmt_ident = is_stmt_ident
|
||||||
}
|
}
|
||||||
.name, .question {
|
.name, .question {
|
||||||
|
|
|
@ -117,3 +117,28 @@ fn test_defer_order() {
|
||||||
assert i == 1
|
assert i == 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_defer_access() {
|
||||||
|
if true {
|
||||||
|
mut i := 0
|
||||||
|
defer {
|
||||||
|
i++
|
||||||
|
assert i == 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_defer_arrays() {
|
||||||
|
mut ia := []int{}
|
||||||
|
defer {
|
||||||
|
ia << 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_defer_str_interpol() {
|
||||||
|
mut t := []string{}
|
||||||
|
defer {
|
||||||
|
t << 'test'
|
||||||
|
t << '${t[0]}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue