mirror of
https://github.com/neovim/neovim.git
synced 2025-09-28 22:18:33 +00:00
vim-patch:9.0.2059: outstanding exceptions may be skipped (#25736)
Problem: outstanding exceptions may be skipped
Solution: When restoring exception state, process remaining outstanding
exceptions
closes: vim/vim#13386
0ab500dede
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
@@ -410,7 +410,8 @@ Any return value of the deferred function is discarded. The function cannot
|
|||||||
be followed by anything, such as "->func" or ".member". Currently `:defer
|
be followed by anything, such as "->func" or ".member". Currently `:defer
|
||||||
GetArg()->TheFunc()` does not work, it may work in a later version.
|
GetArg()->TheFunc()` does not work, it may work in a later version.
|
||||||
|
|
||||||
Errors are reported but do not cause aborting execution of deferred functions.
|
Errors are reported but do not cause aborting execution of deferred functions
|
||||||
|
or altering execution outside of deferred functions.
|
||||||
|
|
||||||
No range is accepted. The function can be a partial with extra arguments, but
|
No range is accepted. The function can be a partial with extra arguments, but
|
||||||
not with a dictionary. *E1300*
|
not with a dictionary. *E1300*
|
||||||
|
@@ -668,17 +668,21 @@ void exception_state_save(exception_state_T *estate)
|
|||||||
estate->estate_did_throw = did_throw;
|
estate->estate_did_throw = did_throw;
|
||||||
estate->estate_need_rethrow = need_rethrow;
|
estate->estate_need_rethrow = need_rethrow;
|
||||||
estate->estate_trylevel = trylevel;
|
estate->estate_trylevel = trylevel;
|
||||||
|
estate->estate_did_emsg = did_emsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restore the current exception state from "estate"
|
/// Restore the current exception state from "estate"
|
||||||
void exception_state_restore(exception_state_T *estate)
|
void exception_state_restore(exception_state_T *estate)
|
||||||
{
|
{
|
||||||
if (current_exception == NULL) {
|
// Handle any outstanding exceptions before restoring the state
|
||||||
current_exception = estate->estate_current_exception;
|
if (did_throw) {
|
||||||
|
handle_did_throw();
|
||||||
}
|
}
|
||||||
did_throw |= estate->estate_did_throw;
|
current_exception = estate->estate_current_exception;
|
||||||
need_rethrow |= estate->estate_need_rethrow;
|
did_throw = estate->estate_did_throw;
|
||||||
trylevel |= estate->estate_trylevel;
|
need_rethrow = estate->estate_need_rethrow;
|
||||||
|
trylevel = estate->estate_trylevel;
|
||||||
|
did_emsg = estate->estate_did_emsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear the current exception state
|
/// Clear the current exception state
|
||||||
@@ -688,6 +692,7 @@ void exception_state_clear(void)
|
|||||||
did_throw = false;
|
did_throw = false;
|
||||||
need_rethrow = false;
|
need_rethrow = false;
|
||||||
trylevel = 0;
|
trylevel = 0;
|
||||||
|
did_emsg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flags specifying the message displayed by report_pending.
|
// Flags specifying the message displayed by report_pending.
|
||||||
|
@@ -126,6 +126,7 @@ struct exception_state_S {
|
|||||||
bool estate_did_throw;
|
bool estate_did_throw;
|
||||||
bool estate_need_rethrow;
|
bool estate_need_rethrow;
|
||||||
int estate_trylevel;
|
int estate_trylevel;
|
||||||
|
int estate_did_emsg;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NVIM_EX_EVAL_DEFS_H
|
#endif // NVIM_EX_EVAL_DEFS_H
|
||||||
|
@@ -827,7 +827,68 @@ func Test_defer_after_exception()
|
|||||||
|
|
||||||
delfunc Defer
|
delfunc Defer
|
||||||
delfunc Foo
|
delfunc Foo
|
||||||
|
delfunc Bar
|
||||||
unlet g:callTrace
|
unlet g:callTrace
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test for multiple deferred function which throw exceptions.
|
||||||
|
" Exceptions thrown by deferred functions should result in error messages but
|
||||||
|
" not propagated into the calling functions.
|
||||||
|
func Test_multidefer_with_exception()
|
||||||
|
let g:callTrace = []
|
||||||
|
func Except()
|
||||||
|
let g:callTrace += [1]
|
||||||
|
throw 'InnerException'
|
||||||
|
let g:callTrace += [2]
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func FirstDefer()
|
||||||
|
let g:callTrace += [3]
|
||||||
|
let g:callTrace += [4]
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func SecondDeferWithExcept()
|
||||||
|
let g:callTrace += [5]
|
||||||
|
call Except()
|
||||||
|
let g:callTrace += [6]
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func ThirdDefer()
|
||||||
|
let g:callTrace += [7]
|
||||||
|
let g:callTrace += [8]
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Foo()
|
||||||
|
let g:callTrace += [9]
|
||||||
|
defer FirstDefer()
|
||||||
|
defer SecondDeferWithExcept()
|
||||||
|
defer ThirdDefer()
|
||||||
|
let g:callTrace += [10]
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
let v:errmsg = ''
|
||||||
|
try
|
||||||
|
let g:callTrace += [11]
|
||||||
|
call Foo()
|
||||||
|
let g:callTrace += [12]
|
||||||
|
catch /TestException/
|
||||||
|
let g:callTrace += [13]
|
||||||
|
catch
|
||||||
|
let g:callTrace += [14]
|
||||||
|
finally
|
||||||
|
let g:callTrace += [15]
|
||||||
|
endtry
|
||||||
|
let g:callTrace += [16]
|
||||||
|
|
||||||
|
call assert_equal('E605: Exception not caught: InnerException', v:errmsg)
|
||||||
|
call assert_equal([11, 9, 10, 7, 8, 5, 1, 3, 4, 12, 15, 16], g:callTrace)
|
||||||
|
|
||||||
|
unlet g:callTrace
|
||||||
|
delfunc Except
|
||||||
|
delfunc FirstDefer
|
||||||
|
delfunc SecondDeferWithExcept
|
||||||
|
delfunc ThirdDefer
|
||||||
|
delfunc Foo
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
Reference in New Issue
Block a user