Skip to content

Commit b04af4c

Browse files
yegappanchrisbra
authored andcommitted
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>
1 parent 27f2e47 commit b04af4c

4 files changed

Lines changed: 146 additions & 1 deletion

File tree

src/errors.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3616,8 +3616,10 @@ EXTERN char e_duplicate_enum_str[]
36163616
INIT(= N_("E1428: Duplicate enum value: %s"));
36173617
EXTERN char e_class_can_only_be_used_in_script[]
36183618
INIT(= N_("E1429: Class can only be used in a script"));
3619+
EXTERN char e_uninitialized_object_var_reference[]
3620+
INIT(= N_("E1430: Uninitialized object variable '%s' referenced"));
36193621
#endif
3620-
// E1429 - E1499 unused (reserved for Vim9 class support)
3622+
// E1431 - E1499 unused (reserved for Vim9 class support)
36213623
EXTERN char e_cannot_mix_positional_and_non_positional_str[]
36223624
INIT(= N_("E1500: Cannot mix positional and non-positional arguments: %s"));
36233625
EXTERN char e_fmt_arg_nr_unused_str[]

src/testdir/test_vim9_class.vim

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11723,4 +11723,120 @@ def Test_use_object_method_in_a_method_call()
1172311723
v9.CheckSourceFailure(lines, 'E1326: Variable "NewCost" not found in object "Foo"')
1172411724
enddef
1172511725

11726+
" Test for referencing an object variable which is not yet initialized
11727+
def Test_uninitialized_object_var()
11728+
var lines =<< trim END
11729+
vim9script
11730+
class Foo
11731+
const two: number = Foo.Two(this)
11732+
const one: number = 1
11733+
11734+
static def Two(that: Foo): number
11735+
return that.one + 2
11736+
enddef
11737+
endclass
11738+
11739+
echo Foo.Two(Foo.new())
11740+
END
11741+
v9.CheckSourceFailure(lines, "E1430: Uninitialized object variable 'one' referenced")
11742+
11743+
lines =<< trim END
11744+
vim9script
11745+
class Foo
11746+
const one: number = Foo.One(this)
11747+
11748+
static def One(that: Foo): number
11749+
return 1
11750+
enddef
11751+
endclass
11752+
11753+
assert_equal(1, Foo.One(Foo.new()))
11754+
END
11755+
v9.CheckSourceSuccess(lines)
11756+
11757+
lines =<< trim END
11758+
vim9script
11759+
class Foo
11760+
const one: number = 1
11761+
const two: number = Foo.Two(this)
11762+
11763+
static def Two(that: Foo): number
11764+
return that.one + 1
11765+
enddef
11766+
endclass
11767+
11768+
assert_equal(2, Foo.Two(Foo.new()))
11769+
END
11770+
v9.CheckSourceSuccess(lines)
11771+
11772+
lines =<< trim END
11773+
vim9script
11774+
class Foo
11775+
const Id: func(any): any = ((_) => (v) => v)(this)
11776+
11777+
static def Id(that: Foo): func(any): any
11778+
return that.Id
11779+
enddef
11780+
endclass
11781+
11782+
assert_equal(5, Foo.Id(Foo.new())(5))
11783+
assert_equal(7, Foo.new().Id(7))
11784+
END
11785+
v9.CheckSourceSuccess(lines)
11786+
11787+
lines =<< trim END
11788+
vim9script
11789+
class Foo
11790+
const Id: func(any): any = ((that) => (_) => that)(this)
11791+
11792+
static def Id(that: Foo): func(any): any
11793+
return that.Id
11794+
enddef
11795+
endclass
11796+
11797+
const Id0: func(any): any = Foo.Id(Foo.new())
11798+
const Id1: func(any): any = Foo.new().Id
11799+
END
11800+
v9.CheckSourceSuccess(lines)
11801+
11802+
lines =<< trim END
11803+
vim9script
11804+
class Foo
11805+
const Id: any = Foo.Id(this)
11806+
11807+
static def Id(that: Foo): any
11808+
return that.Id
11809+
enddef
11810+
endclass
11811+
11812+
const Id2: any = Foo.Id(Foo.new())
11813+
const Id3: any = Foo.new().Id
11814+
END
11815+
v9.CheckSourceFailure(lines, "E1430: Uninitialized object variable 'Id' referenced")
11816+
11817+
lines =<< trim END
11818+
vim9script
11819+
11820+
class Foo
11821+
var x: string = ''
11822+
var Y: func(): string = () => this.x
11823+
endclass
11824+
11825+
var foo = Foo.new('ok')
11826+
assert_equal('ok', foo.Y())
11827+
END
11828+
v9.CheckSourceSuccess(lines)
11829+
11830+
lines =<< trim END
11831+
vim9script
11832+
11833+
class Foo
11834+
var x: string = this.x
11835+
endclass
11836+
11837+
var foo = Foo.new('ok')
11838+
END
11839+
v9.CheckSourceFailure(lines, "E1430: Uninitialized object variable 'x' referenced")
11840+
enddef
11841+
1172611842
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
988,
707709
/**/
708710
987,
709711
/**/

src/vim9execute.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4844,6 +4844,20 @@ exec_instructions(ectx_T *ectx)
48444844
int arg_set = tv->v_type != VAR_UNKNOWN
48454845
&& !(tv->v_type == VAR_SPECIAL
48464846
&& tv->vval.v_number == VVAL_NONE);
4847+
4848+
if (iptr->isn_type == ISN_JUMP_IF_ARG_NOT_SET && !arg_set)
4849+
{
4850+
dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
4851+
+ ectx->ec_dfunc_idx;
4852+
ufunc_T *ufunc = df->df_ufunc;
4853+
// jump_arg_off is negative for arguments
4854+
size_t argidx = ufunc->uf_def_args.ga_len
4855+
+ iptr->isn_arg.jumparg.jump_arg_off
4856+
+ STACK_FRAME_SIZE;
4857+
type_T *t = ufunc->uf_arg_types[argidx];
4858+
tv->v_type = t->tt_type;
4859+
}
4860+
48474861
if (iptr->isn_type == ISN_JUMP_IF_ARG_SET ? arg_set : !arg_set)
48484862
ectx->ec_iidx = iptr->isn_arg.jumparg.jump_where;
48494863
break;
@@ -5718,6 +5732,17 @@ exec_instructions(ectx_T *ectx)
57185732

57195733
// The members are located right after the object struct.
57205734
typval_T *mtv = ((typval_T *)(obj + 1)) + idx;
5735+
if (mtv->v_type == VAR_UNKNOWN)
5736+
{
5737+
// Referencing an object variable (without a type)
5738+
// which is not yet initialized. So the type is not
5739+
// yet known.
5740+
ocmember_T *m = &obj->obj_class->class_obj_members[idx];
5741+
SOURCING_LNUM = iptr->isn_lnum;
5742+
semsg(_(e_uninitialized_object_var_reference),
5743+
m->ocm_name);
5744+
goto on_error;
5745+
}
57215746
copy_tv(mtv, tv);
57225747

57235748
// Unreference the object after getting the member, it may

0 commit comments

Comments
 (0)