mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 9.0.1054: object member can't get type from initializer
Problem: Object member can't get type from initializer. Solution: If there is no type specified try to use the type of the initializer. Check for a valid type.
This commit is contained in:
parent
65b0d16768
commit
74e1274edf
@ -3374,4 +3374,8 @@ EXTERN char e_object_required_found_str[]
|
||||
INIT(= N_("E1327: Object required, found %s"));
|
||||
EXTERN char e_constructor_default_value_must_be_vnone_str[]
|
||||
INIT(= N_("E1328: Constructor default value must be v:none: %s"));
|
||||
EXTERN char e_cannot_get_object_member_type_from_initializer_str[]
|
||||
INIT(= N_("E1329: Cannot get object member type from initializer: %s"));
|
||||
EXTERN char e_invalid_type_for_object_member_str[]
|
||||
INIT(= N_("E1330: Invalid type for object member: %s"));
|
||||
#endif
|
||||
|
@ -13,6 +13,7 @@ int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap);
|
||||
int type_any_or_unknown(type_T *type);
|
||||
int need_convert_to_bool(type_T *type, typval_T *tv);
|
||||
type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags);
|
||||
int valid_declaration_type(type_T *type);
|
||||
type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap);
|
||||
int check_typval_arg_type(type_T *expected, typval_T *actual_tv, char *func_name, int arg_idx);
|
||||
int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where);
|
||||
|
@ -231,7 +231,58 @@ def Test_class_default_new()
|
||||
assert_equal("none", chris.education)
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class Person
|
||||
this.name: string
|
||||
this.age: number = 42
|
||||
this.education: string = "unknown"
|
||||
|
||||
def new(this.name, this.age = v:none, this.education = v:none)
|
||||
enddef
|
||||
endclass
|
||||
|
||||
var missing = Person.new()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E119:')
|
||||
enddef
|
||||
|
||||
def Test_class_object_member_inits()
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
class TextPosition
|
||||
this.lnum: number
|
||||
this.col = 1
|
||||
this.addcol: number = 2
|
||||
endclass
|
||||
|
||||
var pos = TextPosition.new()
|
||||
assert_equal(0, pos.lnum)
|
||||
assert_equal(1, pos.col)
|
||||
assert_equal(2, pos.addcol)
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class TextPosition
|
||||
this.lnum
|
||||
this.col = 1
|
||||
endclass
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1022:')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class TextPosition
|
||||
this.lnum = v:none
|
||||
this.col = 1
|
||||
endclass
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1330:')
|
||||
enddef
|
||||
|
||||
|
||||
|
||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||
|
@ -695,6 +695,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1054,
|
||||
/**/
|
||||
1053,
|
||||
/**/
|
||||
|
@ -125,43 +125,74 @@ ex_class(exarg_T *eap)
|
||||
char_u *varname_end = to_name_end(varname, FALSE);
|
||||
|
||||
char_u *colon = skipwhite(varname_end);
|
||||
// TODO: accept initialization and figure out type from it
|
||||
if (*colon != ':')
|
||||
char_u *type_arg = colon;
|
||||
type_T *type = NULL;
|
||||
if (*colon == ':')
|
||||
{
|
||||
if (VIM_ISWHITE(*varname_end))
|
||||
{
|
||||
semsg(_(e_no_white_space_allowed_before_colon_str),
|
||||
varname);
|
||||
break;
|
||||
}
|
||||
if (!VIM_ISWHITE(colon[1]))
|
||||
{
|
||||
semsg(_(e_white_space_required_after_str_str), ":",
|
||||
varname);
|
||||
break;
|
||||
}
|
||||
type_arg = skipwhite(colon + 1);
|
||||
type = parse_type(&type_arg, &type_list, TRUE);
|
||||
if (type == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
char_u *expr_start = skipwhite(type_arg);
|
||||
char_u *expr_end = expr_start;
|
||||
if (type == NULL && *expr_start != '=')
|
||||
{
|
||||
emsg(_(e_type_or_initialization_required));
|
||||
break;
|
||||
}
|
||||
if (VIM_ISWHITE(*varname_end))
|
||||
{
|
||||
semsg(_(e_no_white_space_allowed_before_colon_str), varname);
|
||||
break;
|
||||
}
|
||||
if (!VIM_ISWHITE(colon[1]))
|
||||
{
|
||||
semsg(_(e_white_space_required_after_str_str), ":", varname);
|
||||
break;
|
||||
}
|
||||
|
||||
char_u *type_arg = skipwhite(colon + 1);
|
||||
type_T *type = parse_type(&type_arg, &type_list, TRUE);
|
||||
if (type == NULL)
|
||||
break;
|
||||
|
||||
char_u *expr_start = skipwhite(type_arg);
|
||||
if (*expr_start == '=' && (!VIM_ISWHITE(expr_start[-1])
|
||||
|| !VIM_ISWHITE(expr_start[1])))
|
||||
if (*expr_start == '=')
|
||||
{
|
||||
semsg(_(e_white_space_required_before_and_after_str_at_str),
|
||||
if (!VIM_ISWHITE(expr_start[-1]) || !VIM_ISWHITE(expr_start[1]))
|
||||
{
|
||||
semsg(_(e_white_space_required_before_and_after_str_at_str),
|
||||
"=", type_arg);
|
||||
break;
|
||||
}
|
||||
expr_start = skipwhite(expr_start + 1);
|
||||
break;
|
||||
}
|
||||
expr_start = skipwhite(expr_start + 1);
|
||||
|
||||
char_u *expr_end = expr_start;
|
||||
evalarg_T evalarg;
|
||||
init_evalarg(&evalarg);
|
||||
skip_expr(&expr_end, &evalarg);
|
||||
clear_evalarg(&evalarg, NULL);
|
||||
expr_end = expr_start;
|
||||
evalarg_T evalarg;
|
||||
fill_evalarg_from_eap(&evalarg, eap, FALSE);
|
||||
skip_expr(&expr_end, &evalarg);
|
||||
|
||||
if (type == NULL)
|
||||
{
|
||||
// No type specified, use the type of the initializer.
|
||||
typval_T tv;
|
||||
tv.v_type = VAR_UNKNOWN;
|
||||
char_u *expr = expr_start;
|
||||
int res = eval0(expr, &tv, eap, &evalarg);
|
||||
|
||||
if (res == OK)
|
||||
type = typval2type(&tv, get_copyID(), &type_list,
|
||||
TVTT_DO_MEMBER);
|
||||
if (type == NULL)
|
||||
{
|
||||
semsg(_(e_cannot_get_object_member_type_from_initializer_str),
|
||||
expr_start);
|
||||
clear_evalarg(&evalarg, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
clear_evalarg(&evalarg, NULL);
|
||||
}
|
||||
if (!valid_declaration_type(type))
|
||||
break;
|
||||
|
||||
if (ga_grow(&objmembers, 1) == FAIL)
|
||||
break;
|
||||
|
@ -425,6 +425,17 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags)
|
||||
return &t_number;
|
||||
if (tv->v_type == VAR_BOOL)
|
||||
return &t_bool;
|
||||
if (tv->v_type == VAR_SPECIAL)
|
||||
{
|
||||
if (tv->vval.v_number == VVAL_NULL)
|
||||
return &t_null;
|
||||
if (tv->vval.v_number == VVAL_NONE)
|
||||
return &t_none;
|
||||
if (tv->vval.v_number == VVAL_TRUE
|
||||
|| tv->vval.v_number == VVAL_TRUE)
|
||||
return &t_bool;
|
||||
return &t_unknown;
|
||||
}
|
||||
if (tv->v_type == VAR_STRING)
|
||||
return &t_string;
|
||||
if (tv->v_type == VAR_BLOB)
|
||||
@ -619,6 +630,25 @@ typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags)
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if "type" can be used for a variable declaration.
|
||||
* Give an error and return FALSE if not.
|
||||
*/
|
||||
int
|
||||
valid_declaration_type(type_T *type)
|
||||
{
|
||||
if (type->tt_type == VAR_SPECIAL // null, none
|
||||
|| type->tt_type == VAR_VOID)
|
||||
{
|
||||
char *tofree = NULL;
|
||||
char *name = type_name(type, &tofree);
|
||||
semsg(_(e_invalid_type_for_object_member_str), name);
|
||||
vim_free(tofree);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a type_T for a typval_T, used for v: variables.
|
||||
* "type_list" is used to temporarily create types in.
|
||||
|
Loading…
x
Reference in New Issue
Block a user