forked from aniani/vim
patch 9.1.0988: Vim9: no error when using uninitialized var in new()
Problem: Vim9: no error when using uninitialized var in new() (lifepillar, Aliaksei Budavei) Solution: Give an error if an uninitialized object variable is referenced in new() (Yegappan Lakshmanan) fixes: #14411 fixes: #16344 closes: #16374 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
27f2e473e1
commit
b04af4cc96
@@ -3616,8 +3616,10 @@ EXTERN char e_duplicate_enum_str[]
|
|||||||
INIT(= N_("E1428: Duplicate enum value: %s"));
|
INIT(= N_("E1428: Duplicate enum value: %s"));
|
||||||
EXTERN char e_class_can_only_be_used_in_script[]
|
EXTERN char e_class_can_only_be_used_in_script[]
|
||||||
INIT(= N_("E1429: Class can only be used in a script"));
|
INIT(= N_("E1429: Class can only be used in a script"));
|
||||||
|
EXTERN char e_uninitialized_object_var_reference[]
|
||||||
|
INIT(= N_("E1430: Uninitialized object variable '%s' referenced"));
|
||||||
#endif
|
#endif
|
||||||
// E1429 - E1499 unused (reserved for Vim9 class support)
|
// E1431 - E1499 unused (reserved for Vim9 class support)
|
||||||
EXTERN char e_cannot_mix_positional_and_non_positional_str[]
|
EXTERN char e_cannot_mix_positional_and_non_positional_str[]
|
||||||
INIT(= N_("E1500: Cannot mix positional and non-positional arguments: %s"));
|
INIT(= N_("E1500: Cannot mix positional and non-positional arguments: %s"));
|
||||||
EXTERN char e_fmt_arg_nr_unused_str[]
|
EXTERN char e_fmt_arg_nr_unused_str[]
|
||||||
|
@@ -11723,4 +11723,120 @@ def Test_use_object_method_in_a_method_call()
|
|||||||
v9.CheckSourceFailure(lines, 'E1326: Variable "NewCost" not found in object "Foo"')
|
v9.CheckSourceFailure(lines, 'E1326: Variable "NewCost" not found in object "Foo"')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
" Test for referencing an object variable which is not yet initialized
|
||||||
|
def Test_uninitialized_object_var()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class Foo
|
||||||
|
const two: number = Foo.Two(this)
|
||||||
|
const one: number = 1
|
||||||
|
|
||||||
|
static def Two(that: Foo): number
|
||||||
|
return that.one + 2
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
echo Foo.Two(Foo.new())
|
||||||
|
END
|
||||||
|
v9.CheckSourceFailure(lines, "E1430: Uninitialized object variable 'one' referenced")
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class Foo
|
||||||
|
const one: number = Foo.One(this)
|
||||||
|
|
||||||
|
static def One(that: Foo): number
|
||||||
|
return 1
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
assert_equal(1, Foo.One(Foo.new()))
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class Foo
|
||||||
|
const one: number = 1
|
||||||
|
const two: number = Foo.Two(this)
|
||||||
|
|
||||||
|
static def Two(that: Foo): number
|
||||||
|
return that.one + 1
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
assert_equal(2, Foo.Two(Foo.new()))
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class Foo
|
||||||
|
const Id: func(any): any = ((_) => (v) => v)(this)
|
||||||
|
|
||||||
|
static def Id(that: Foo): func(any): any
|
||||||
|
return that.Id
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
assert_equal(5, Foo.Id(Foo.new())(5))
|
||||||
|
assert_equal(7, Foo.new().Id(7))
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class Foo
|
||||||
|
const Id: func(any): any = ((that) => (_) => that)(this)
|
||||||
|
|
||||||
|
static def Id(that: Foo): func(any): any
|
||||||
|
return that.Id
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
const Id0: func(any): any = Foo.Id(Foo.new())
|
||||||
|
const Id1: func(any): any = Foo.new().Id
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class Foo
|
||||||
|
const Id: any = Foo.Id(this)
|
||||||
|
|
||||||
|
static def Id(that: Foo): any
|
||||||
|
return that.Id
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
const Id2: any = Foo.Id(Foo.new())
|
||||||
|
const Id3: any = Foo.new().Id
|
||||||
|
END
|
||||||
|
v9.CheckSourceFailure(lines, "E1430: Uninitialized object variable 'Id' referenced")
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class Foo
|
||||||
|
var x: string = ''
|
||||||
|
var Y: func(): string = () => this.x
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var foo = Foo.new('ok')
|
||||||
|
assert_equal('ok', foo.Y())
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class Foo
|
||||||
|
var x: string = this.x
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var foo = Foo.new('ok')
|
||||||
|
END
|
||||||
|
v9.CheckSourceFailure(lines, "E1430: Uninitialized object variable 'x' referenced")
|
||||||
|
enddef
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@@ -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 */
|
||||||
|
/**/
|
||||||
|
988,
|
||||||
/**/
|
/**/
|
||||||
987,
|
987,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -4844,6 +4844,20 @@ exec_instructions(ectx_T *ectx)
|
|||||||
int arg_set = tv->v_type != VAR_UNKNOWN
|
int arg_set = tv->v_type != VAR_UNKNOWN
|
||||||
&& !(tv->v_type == VAR_SPECIAL
|
&& !(tv->v_type == VAR_SPECIAL
|
||||||
&& tv->vval.v_number == VVAL_NONE);
|
&& tv->vval.v_number == VVAL_NONE);
|
||||||
|
|
||||||
|
if (iptr->isn_type == ISN_JUMP_IF_ARG_NOT_SET && !arg_set)
|
||||||
|
{
|
||||||
|
dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
|
||||||
|
+ ectx->ec_dfunc_idx;
|
||||||
|
ufunc_T *ufunc = df->df_ufunc;
|
||||||
|
// jump_arg_off is negative for arguments
|
||||||
|
size_t argidx = ufunc->uf_def_args.ga_len
|
||||||
|
+ iptr->isn_arg.jumparg.jump_arg_off
|
||||||
|
+ STACK_FRAME_SIZE;
|
||||||
|
type_T *t = ufunc->uf_arg_types[argidx];
|
||||||
|
tv->v_type = t->tt_type;
|
||||||
|
}
|
||||||
|
|
||||||
if (iptr->isn_type == ISN_JUMP_IF_ARG_SET ? arg_set : !arg_set)
|
if (iptr->isn_type == ISN_JUMP_IF_ARG_SET ? arg_set : !arg_set)
|
||||||
ectx->ec_iidx = iptr->isn_arg.jumparg.jump_where;
|
ectx->ec_iidx = iptr->isn_arg.jumparg.jump_where;
|
||||||
break;
|
break;
|
||||||
@@ -5718,6 +5732,17 @@ exec_instructions(ectx_T *ectx)
|
|||||||
|
|
||||||
// The members are located right after the object struct.
|
// The members are located right after the object struct.
|
||||||
typval_T *mtv = ((typval_T *)(obj + 1)) + idx;
|
typval_T *mtv = ((typval_T *)(obj + 1)) + idx;
|
||||||
|
if (mtv->v_type == VAR_UNKNOWN)
|
||||||
|
{
|
||||||
|
// Referencing an object variable (without a type)
|
||||||
|
// which is not yet initialized. So the type is not
|
||||||
|
// yet known.
|
||||||
|
ocmember_T *m = &obj->obj_class->class_obj_members[idx];
|
||||||
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
|
semsg(_(e_uninitialized_object_var_reference),
|
||||||
|
m->ocm_name);
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
copy_tv(mtv, tv);
|
copy_tv(mtv, tv);
|
||||||
|
|
||||||
// Unreference the object after getting the member, it may
|
// Unreference the object after getting the member, it may
|
||||||
|
Reference in New Issue
Block a user