mirror of
https://github.com/vim/vim
synced 2025-07-16 01:01:58 +00:00
patch 9.0.2059: outstanding exceptions may be skipped
Problem: outstanding exceptions may be skipped Solution: When restoring exception state, process remaining outstanding exceptions closes: #13386 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
committed by
Christian Brabandt
parent
a36acb7ac4
commit
0ab500dede
@ -443,7 +443,8 @@ Any return value of the deferred function is discarded. The function cannot
|
||||
be followed by anything, such as "->func" or ".member". Currently `:defer
|
||||
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
|
||||
not with a dictionary. *E1300*
|
||||
|
@ -28,7 +28,8 @@ Vim9 classes, objects, interfaces, types and enums.
|
||||
The fancy term is "object-oriented programming". You can find lots of study
|
||||
material on this subject. Here we document what |Vim9| script provides,
|
||||
assuming you know the basics already. Added are helpful hints about how to
|
||||
use this functionality effectively.
|
||||
use this functionality effectively. Vim9 classes and objects cannot be used
|
||||
in legacy Vim scripts and legacy functions.
|
||||
|
||||
The basic item is an object:
|
||||
- An object stores state. It contains one or more variables that can each
|
||||
|
@ -757,6 +757,7 @@ exception_state_save(exception_state_T *estate)
|
||||
estate->estate_did_throw = did_throw;
|
||||
estate->estate_need_rethrow = need_rethrow;
|
||||
estate->estate_trylevel = trylevel;
|
||||
estate->estate_did_emsg = did_emsg;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -765,11 +766,14 @@ exception_state_save(exception_state_T *estate)
|
||||
void
|
||||
exception_state_restore(exception_state_T *estate)
|
||||
{
|
||||
if (current_exception == NULL)
|
||||
current_exception = estate->estate_current_exception;
|
||||
did_throw |= estate->estate_did_throw;
|
||||
need_rethrow |= estate->estate_need_rethrow;
|
||||
trylevel |= estate->estate_trylevel;
|
||||
// Handle any outstanding exceptions before restoring the state
|
||||
if (did_throw)
|
||||
handle_did_throw();
|
||||
current_exception = estate->estate_current_exception;
|
||||
did_throw = estate->estate_did_throw;
|
||||
need_rethrow = estate->estate_need_rethrow;
|
||||
trylevel = estate->estate_trylevel;
|
||||
did_emsg = estate->estate_did_emsg;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -782,6 +786,7 @@ exception_state_clear(void)
|
||||
did_throw = FALSE;
|
||||
need_rethrow = FALSE;
|
||||
trylevel = 0;
|
||||
did_emsg = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1099,6 +1099,7 @@ struct exception_state_S
|
||||
int estate_did_throw;
|
||||
int estate_need_rethrow;
|
||||
int estate_trylevel;
|
||||
int estate_did_emsg;
|
||||
};
|
||||
|
||||
#ifdef FEAT_SYN_HL
|
||||
|
@ -904,7 +904,68 @@ func Test_defer_after_exception()
|
||||
|
||||
delfunc Defer
|
||||
delfunc Foo
|
||||
delfunc Bar
|
||||
unlet g:callTrace
|
||||
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
|
||||
|
@ -8347,10 +8347,10 @@ def Test_class_variable_as_operands()
|
||||
public static TruthyFn: func
|
||||
static list: list<any> = []
|
||||
static four: number = 4
|
||||
static hello: string = 'hello'
|
||||
static str: string = 'hello'
|
||||
|
||||
static def Hello(): string
|
||||
return hello
|
||||
static def Str(): string
|
||||
return str
|
||||
enddef
|
||||
|
||||
static def Four(): number
|
||||
@ -8374,8 +8374,17 @@ def Test_class_variable_as_operands()
|
||||
assert_equal(16, 1 << Tests.four)
|
||||
assert_equal(8, Tests.four + four)
|
||||
assert_equal(8, four + Tests.four)
|
||||
assert_equal('hellohello', Tests.hello .. hello)
|
||||
assert_equal('hellohello', hello .. Tests.hello)
|
||||
assert_equal('hellohello', Tests.str .. str)
|
||||
assert_equal('hellohello', str .. Tests.str)
|
||||
|
||||
# Using class variable for list indexing
|
||||
var l = range(10)
|
||||
assert_equal(4, l[Tests.four])
|
||||
assert_equal([4, 5, 6], l[Tests.four : Tests.four + 2])
|
||||
|
||||
# Using class variable for Dict key
|
||||
var d = {hello: 'abc'}
|
||||
assert_equal('abc', d[Tests.str])
|
||||
enddef
|
||||
endclass
|
||||
|
||||
@ -8390,8 +8399,17 @@ def Test_class_variable_as_operands()
|
||||
assert_equal(16, 1 << Tests.four)
|
||||
assert_equal(8, Tests.four + Tests.Four())
|
||||
assert_equal(8, Tests.Four() + Tests.four)
|
||||
assert_equal('hellohello', Tests.hello .. Tests.Hello())
|
||||
assert_equal('hellohello', Tests.Hello() .. Tests.hello)
|
||||
assert_equal('hellohello', Tests.str .. Tests.Str())
|
||||
assert_equal('hellohello', Tests.Str() .. Tests.str)
|
||||
|
||||
# Using class variable for list indexing
|
||||
var l = range(10)
|
||||
assert_equal(4, l[Tests.four])
|
||||
assert_equal([4, 5, 6], l[Tests.four : Tests.four + 2])
|
||||
|
||||
# Using class variable for Dict key
|
||||
var d = {hello: 'abc'}
|
||||
assert_equal('abc', d[Tests.str])
|
||||
enddef
|
||||
|
||||
Tests.TruthyFn = Tests.Truthy
|
||||
@ -8409,8 +8427,17 @@ def Test_class_variable_as_operands()
|
||||
assert_equal(16, 1 << Tests.four)
|
||||
assert_equal(8, Tests.four + Tests.Four())
|
||||
assert_equal(8, Tests.Four() + Tests.four)
|
||||
assert_equal('hellohello', Tests.hello .. Tests.Hello())
|
||||
assert_equal('hellohello', Tests.Hello() .. Tests.hello)
|
||||
assert_equal('hellohello', Tests.str .. Tests.Str())
|
||||
assert_equal('hellohello', Tests.Str() .. Tests.str)
|
||||
|
||||
# Using class variable for list indexing
|
||||
var l = range(10)
|
||||
assert_equal(4, l[Tests.four])
|
||||
assert_equal([4, 5, 6], l[Tests.four : Tests.four + 2])
|
||||
|
||||
# Using class variable for Dict key
|
||||
var d = {hello: 'abc'}
|
||||
assert_equal('abc', d[Tests.str])
|
||||
END
|
||||
v9.CheckSourceSuccess(lines)
|
||||
enddef
|
||||
|
@ -4725,6 +4725,64 @@ def Test_defer_after_exception()
|
||||
v9.CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
" 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.
|
||||
def Test_multidefer_with_exception()
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
|
||||
var callTrace: list<number> = []
|
||||
def Except()
|
||||
callTrace += [1]
|
||||
throw 'InnerException'
|
||||
callTrace += [2]
|
||||
enddef
|
||||
|
||||
def FirstDefer()
|
||||
callTrace += [3]
|
||||
callTrace += [4]
|
||||
enddef
|
||||
|
||||
def SecondDeferWithExcept()
|
||||
callTrace += [5]
|
||||
Except()
|
||||
callTrace += [6]
|
||||
enddef
|
||||
|
||||
def ThirdDefer()
|
||||
callTrace += [7]
|
||||
callTrace += [8]
|
||||
enddef
|
||||
|
||||
def Foo()
|
||||
callTrace += [9]
|
||||
defer FirstDefer()
|
||||
defer SecondDeferWithExcept()
|
||||
defer ThirdDefer()
|
||||
callTrace += [10]
|
||||
enddef
|
||||
|
||||
v:errmsg = ''
|
||||
try
|
||||
callTrace += [11]
|
||||
Foo()
|
||||
callTrace += [12]
|
||||
catch /TestException/
|
||||
callTrace += [13]
|
||||
catch
|
||||
callTrace += [14]
|
||||
finally
|
||||
callTrace += [15]
|
||||
endtry
|
||||
callTrace += [16]
|
||||
|
||||
assert_equal('E605: Exception not caught: InnerException', v:errmsg)
|
||||
assert_equal([11, 9, 10, 7, 8, 5, 1, 3, 4, 12, 15, 16], callTrace)
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
" Keep this last, it messes up highlighting.
|
||||
def Test_substitute_cmd()
|
||||
new
|
||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
2059,
|
||||
/**/
|
||||
2058,
|
||||
/**/
|
||||
|
@ -2340,8 +2340,7 @@ class_object_index(
|
||||
}
|
||||
|
||||
if (did_emsg == did_emsg_save)
|
||||
member_not_found_msg(cl, is_object ? VAR_OBJECT : VAR_CLASS, name,
|
||||
len);
|
||||
member_not_found_msg(cl, rettv->v_type, name, len);
|
||||
}
|
||||
|
||||
return FAIL;
|
||||
|
Reference in New Issue
Block a user