mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04: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
|
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*
|
||||||
|
@@ -28,7 +28,8 @@ Vim9 classes, objects, interfaces, types and enums.
|
|||||||
The fancy term is "object-oriented programming". You can find lots of study
|
The fancy term is "object-oriented programming". You can find lots of study
|
||||||
material on this subject. Here we document what |Vim9| script provides,
|
material on this subject. Here we document what |Vim9| script provides,
|
||||||
assuming you know the basics already. Added are helpful hints about how to
|
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:
|
The basic item is an object:
|
||||||
- An object stores state. It contains one or more variables that can each
|
- 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_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -765,11 +766,14 @@ exception_state_save(exception_state_T *estate)
|
|||||||
void
|
void
|
||||||
exception_state_restore(exception_state_T *estate)
|
exception_state_restore(exception_state_T *estate)
|
||||||
{
|
{
|
||||||
if (current_exception == NULL)
|
// Handle any outstanding exceptions before restoring the state
|
||||||
|
if (did_throw)
|
||||||
|
handle_did_throw();
|
||||||
current_exception = estate->estate_current_exception;
|
current_exception = estate->estate_current_exception;
|
||||||
did_throw |= estate->estate_did_throw;
|
did_throw = estate->estate_did_throw;
|
||||||
need_rethrow |= estate->estate_need_rethrow;
|
need_rethrow = estate->estate_need_rethrow;
|
||||||
trylevel |= estate->estate_trylevel;
|
trylevel = estate->estate_trylevel;
|
||||||
|
did_emsg = estate->estate_did_emsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -782,6 +786,7 @@ exception_state_clear(void)
|
|||||||
did_throw = FALSE;
|
did_throw = FALSE;
|
||||||
need_rethrow = FALSE;
|
need_rethrow = FALSE;
|
||||||
trylevel = 0;
|
trylevel = 0;
|
||||||
|
did_emsg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -1099,6 +1099,7 @@ struct exception_state_S
|
|||||||
int estate_did_throw;
|
int estate_did_throw;
|
||||||
int estate_need_rethrow;
|
int estate_need_rethrow;
|
||||||
int estate_trylevel;
|
int estate_trylevel;
|
||||||
|
int estate_did_emsg;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef FEAT_SYN_HL
|
#ifdef FEAT_SYN_HL
|
||||||
|
@@ -904,7 +904,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
|
||||||
|
@@ -8347,10 +8347,10 @@ def Test_class_variable_as_operands()
|
|||||||
public static TruthyFn: func
|
public static TruthyFn: func
|
||||||
static list: list<any> = []
|
static list: list<any> = []
|
||||||
static four: number = 4
|
static four: number = 4
|
||||||
static hello: string = 'hello'
|
static str: string = 'hello'
|
||||||
|
|
||||||
static def Hello(): string
|
static def Str(): string
|
||||||
return hello
|
return str
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
static def Four(): number
|
static def Four(): number
|
||||||
@@ -8374,8 +8374,17 @@ def Test_class_variable_as_operands()
|
|||||||
assert_equal(16, 1 << Tests.four)
|
assert_equal(16, 1 << Tests.four)
|
||||||
assert_equal(8, Tests.four + four)
|
assert_equal(8, Tests.four + four)
|
||||||
assert_equal(8, four + Tests.four)
|
assert_equal(8, four + Tests.four)
|
||||||
assert_equal('hellohello', Tests.hello .. hello)
|
assert_equal('hellohello', Tests.str .. str)
|
||||||
assert_equal('hellohello', hello .. Tests.hello)
|
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
|
enddef
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
@@ -8390,8 +8399,17 @@ def Test_class_variable_as_operands()
|
|||||||
assert_equal(16, 1 << Tests.four)
|
assert_equal(16, 1 << Tests.four)
|
||||||
assert_equal(8, Tests.four + Tests.Four())
|
assert_equal(8, Tests.four + 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.str .. Tests.Str())
|
||||||
assert_equal('hellohello', Tests.Hello() .. Tests.hello)
|
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
|
enddef
|
||||||
|
|
||||||
Tests.TruthyFn = Tests.Truthy
|
Tests.TruthyFn = Tests.Truthy
|
||||||
@@ -8409,8 +8427,17 @@ def Test_class_variable_as_operands()
|
|||||||
assert_equal(16, 1 << Tests.four)
|
assert_equal(16, 1 << Tests.four)
|
||||||
assert_equal(8, Tests.four + Tests.Four())
|
assert_equal(8, Tests.four + 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.str .. Tests.Str())
|
||||||
assert_equal('hellohello', Tests.Hello() .. Tests.hello)
|
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
|
END
|
||||||
v9.CheckSourceSuccess(lines)
|
v9.CheckSourceSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
@@ -4725,6 +4725,64 @@ def Test_defer_after_exception()
|
|||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
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.
|
" Keep this last, it messes up highlighting.
|
||||||
def Test_substitute_cmd()
|
def Test_substitute_cmd()
|
||||||
new
|
new
|
||||||
|
@@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2059,
|
||||||
/**/
|
/**/
|
||||||
2058,
|
2058,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -2340,8 +2340,7 @@ class_object_index(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (did_emsg == did_emsg_save)
|
if (did_emsg == did_emsg_save)
|
||||||
member_not_found_msg(cl, is_object ? VAR_OBJECT : VAR_CLASS, name,
|
member_not_found_msg(cl, rettv->v_type, name, len);
|
||||||
len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
Reference in New Issue
Block a user