Mercurial > vim
comparison src/vim9type.c @ 26925:4e77f9961650 v8.2.3991
patch 8.2.3991: Vim9: error when extending dict<any>
Commit: https://github.com/vim/vim/commit/114dbda7858df956161c0adba5d4d8279645ff67
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Jan 3 12:28:03 2022 +0000
patch 8.2.3991: Vim9: error when extending dict<any>
Problem: Vim9: error when extending dict<any> with another type that it was
initialized with.
Solution: Also set the type for dict<any> if the initializer has a more
specific type. (closes #9461)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 03 Jan 2022 13:30:04 +0100 |
parents | eb6d56ab4858 |
children | ccb9be1cdd71 |
comparison
equal
deleted
inserted
replaced
26924:9a1e933647aa | 26925:4e77f9961650 |
---|---|
250 } | 250 } |
251 | 251 |
252 /* | 252 /* |
253 * Get a type_T for a typval_T. | 253 * Get a type_T for a typval_T. |
254 * "type_gap" is used to temporarily create types in. | 254 * "type_gap" is used to temporarily create types in. |
255 * When "do_member" is TRUE also get the member type, otherwise use "any". | 255 * When "flags" has TVTT_DO_MEMBER also get the member type, otherwise use |
256 * "any". | |
257 * When "flags" has TVTT_MORE_SPECIFIC get the more specific member type if it | |
258 * is "any". | |
256 */ | 259 */ |
257 static type_T * | 260 static type_T * |
258 typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int do_member) | 261 typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags) |
259 { | 262 { |
260 type_T *type; | 263 type_T *type; |
261 type_T *member_type = NULL; | 264 type_T *member_type = NULL; |
262 int argcount = 0; | 265 int argcount = 0; |
263 int min_argcount = 0; | 266 int min_argcount = 0; |
276 list_T *l = tv->vval.v_list; | 279 list_T *l = tv->vval.v_list; |
277 listitem_T *li; | 280 listitem_T *li; |
278 | 281 |
279 if (l == NULL || (l->lv_first == NULL && l->lv_type == NULL)) | 282 if (l == NULL || (l->lv_first == NULL && l->lv_type == NULL)) |
280 return &t_list_empty; | 283 return &t_list_empty; |
281 if (!do_member) | 284 if ((flags & TVTT_DO_MEMBER) == 0) |
282 return &t_list_any; | 285 return &t_list_any; |
283 if (l->lv_type != NULL) | 286 // If the type is list<any> go through the members, it may end up a |
287 // more specific type. | |
288 if (l->lv_type != NULL && (l->lv_first == NULL | |
289 || (flags & TVTT_MORE_SPECIFIC) == 0 | |
290 || l->lv_type->tt_member != &t_any)) | |
284 return l->lv_type; | 291 return l->lv_type; |
285 if (l->lv_first == &range_list_item) | 292 if (l->lv_first == &range_list_item) |
286 return &t_list_number; | 293 return &t_list_number; |
287 if (l->lv_copyID == copyID) | 294 if (l->lv_copyID == copyID) |
288 // avoid recursion | 295 // avoid recursion |
289 return &t_list_any; | 296 return &t_list_any; |
290 l->lv_copyID = copyID; | 297 l->lv_copyID = copyID; |
291 | 298 |
292 // Use the common type of all members. | 299 // Use the common type of all members. |
293 member_type = typval2type(&l->lv_first->li_tv, copyID, type_gap, TRUE); | 300 member_type = typval2type(&l->lv_first->li_tv, copyID, type_gap, |
301 TVTT_DO_MEMBER); | |
294 for (li = l->lv_first->li_next; li != NULL; li = li->li_next) | 302 for (li = l->lv_first->li_next; li != NULL; li = li->li_next) |
295 common_type(typval2type(&li->li_tv, copyID, type_gap, TRUE), | 303 common_type(typval2type(&li->li_tv, copyID, type_gap, |
304 TVTT_DO_MEMBER), | |
296 member_type, &member_type, type_gap); | 305 member_type, &member_type, type_gap); |
297 return get_list_type(member_type, type_gap); | 306 return get_list_type(member_type, type_gap); |
298 } | 307 } |
299 | 308 |
300 if (tv->v_type == VAR_DICT) | 309 if (tv->v_type == VAR_DICT) |
303 typval_T *value; | 312 typval_T *value; |
304 dict_T *d = tv->vval.v_dict; | 313 dict_T *d = tv->vval.v_dict; |
305 | 314 |
306 if (d == NULL || (d->dv_hashtab.ht_used == 0 && d->dv_type == NULL)) | 315 if (d == NULL || (d->dv_hashtab.ht_used == 0 && d->dv_type == NULL)) |
307 return &t_dict_empty; | 316 return &t_dict_empty; |
308 if (!do_member) | 317 if ((flags & TVTT_DO_MEMBER) == 0) |
309 return &t_dict_any; | 318 return &t_dict_any; |
310 if (d->dv_type != NULL) | 319 // If the type is dict<any> go through the members, it may end up a |
320 // more specific type. | |
321 if (d->dv_type != NULL && (d->dv_hashtab.ht_used == 0 | |
322 || (flags & TVTT_MORE_SPECIFIC) == 0 | |
323 || d->dv_type->tt_member != &t_any)) | |
311 return d->dv_type; | 324 return d->dv_type; |
312 if (d->dv_copyID == copyID) | 325 if (d->dv_copyID == copyID) |
313 // avoid recursion | 326 // avoid recursion |
314 return &t_dict_any; | 327 return &t_dict_any; |
315 d->dv_copyID = copyID; | 328 d->dv_copyID = copyID; |
316 | 329 |
317 // Use the common type of all values. | 330 // Use the common type of all values. |
318 dict_iterate_start(tv, &iter); | 331 dict_iterate_start(tv, &iter); |
319 dict_iterate_next(&iter, &value); | 332 dict_iterate_next(&iter, &value); |
320 member_type = typval2type(value, copyID, type_gap, TRUE); | 333 member_type = typval2type(value, copyID, type_gap, TVTT_DO_MEMBER); |
321 while (dict_iterate_next(&iter, &value) != NULL) | 334 while (dict_iterate_next(&iter, &value) != NULL) |
322 common_type(typval2type(value, copyID, type_gap, TRUE), | 335 common_type(typval2type(value, copyID, type_gap, TVTT_DO_MEMBER), |
323 member_type, &member_type, type_gap); | 336 member_type, &member_type, type_gap); |
324 return get_dict_type(member_type, type_gap); | 337 return get_dict_type(member_type, type_gap); |
325 } | 338 } |
326 | 339 |
327 if (tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) | 340 if (tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) |
422 } | 435 } |
423 | 436 |
424 /* | 437 /* |
425 * Get a type_T for a typval_T. | 438 * Get a type_T for a typval_T. |
426 * "type_list" is used to temporarily create types in. | 439 * "type_list" is used to temporarily create types in. |
427 * When "do_member" is TRUE also get the member type, otherwise use "any". | 440 * When "flags" has TVTT_DO_MEMBER also get the member type, otherwise use |
441 * "any". | |
442 * When "flags" has TVTT_MORE_SPECIFIC get the most specific member type. | |
428 */ | 443 */ |
429 type_T * | 444 type_T * |
430 typval2type(typval_T *tv, int copyID, garray_T *type_gap, int do_member) | 445 typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags) |
431 { | 446 { |
432 type_T *type = typval2type_int(tv, copyID, type_gap, do_member); | 447 type_T *type = typval2type_int(tv, copyID, type_gap, flags); |
433 | 448 |
434 if (type != NULL && type != &t_bool | 449 if (type != NULL && type != &t_bool |
435 && (tv->v_type == VAR_NUMBER | 450 && (tv->v_type == VAR_NUMBER |
436 && (tv->vval.v_number == 0 || tv->vval.v_number == 1))) | 451 && (tv->vval.v_number == 0 || tv->vval.v_number == 1))) |
437 // Number 0 and 1 and expression with "&&" or "||" can also be used for | 452 // Number 0 and 1 and expression with "&&" or "||" can also be used for |
449 { | 464 { |
450 if (tv->v_type == VAR_LIST) // e.g. for v:oldfiles | 465 if (tv->v_type == VAR_LIST) // e.g. for v:oldfiles |
451 return &t_list_string; | 466 return &t_list_string; |
452 if (tv->v_type == VAR_DICT) // e.g. for v:completed_item | 467 if (tv->v_type == VAR_DICT) // e.g. for v:completed_item |
453 return &t_dict_any; | 468 return &t_dict_any; |
454 return typval2type(tv, get_copyID(), type_gap, TRUE); | 469 return typval2type(tv, get_copyID(), type_gap, TVTT_DO_MEMBER); |
455 } | 470 } |
456 | 471 |
457 int | 472 int |
458 check_typval_arg_type( | 473 check_typval_arg_type( |
459 type_T *expected, | 474 type_T *expected, |
491 emsg(_(e_function_reference_is_not_set)); | 506 emsg(_(e_function_reference_is_not_set)); |
492 return FAIL; | 507 return FAIL; |
493 } | 508 } |
494 | 509 |
495 ga_init2(&type_list, sizeof(type_T *), 10); | 510 ga_init2(&type_list, sizeof(type_T *), 10); |
496 actual_type = typval2type(actual_tv, get_copyID(), &type_list, TRUE); | 511 |
512 // When the actual type is list<any> or dict<any> go through the values to | |
513 // possibly get a more specific type. | |
514 actual_type = typval2type(actual_tv, get_copyID(), &type_list, | |
515 TVTT_DO_MEMBER | TVTT_MORE_SPECIFIC); | |
497 if (actual_type != NULL) | 516 if (actual_type != NULL) |
498 { | 517 { |
499 res = check_type_maybe(expected, actual_type, TRUE, where); | 518 res = check_type_maybe(expected, actual_type, TRUE, where); |
500 if (res == MAYBE && !(actual_type->tt_type == VAR_FUNC | 519 if (res == MAYBE && !(actual_type->tt_type == VAR_FUNC |
501 && actual_type->tt_member == &t_unknown)) | 520 && actual_type->tt_member == &t_unknown)) |
1344 char *tofree; | 1363 char *tofree; |
1345 char *name; | 1364 char *name; |
1346 | 1365 |
1347 rettv->v_type = VAR_STRING; | 1366 rettv->v_type = VAR_STRING; |
1348 ga_init2(&type_list, sizeof(type_T *), 10); | 1367 ga_init2(&type_list, sizeof(type_T *), 10); |
1349 type = typval2type(argvars, get_copyID(), &type_list, TRUE); | 1368 type = typval2type(argvars, get_copyID(), &type_list, TVTT_DO_MEMBER); |
1350 name = type_name(type, &tofree); | 1369 name = type_name(type, &tofree); |
1351 if (tofree != NULL) | 1370 if (tofree != NULL) |
1352 rettv->vval.v_string = (char_u *)tofree; | 1371 rettv->vval.v_string = (char_u *)tofree; |
1353 else | 1372 else |
1354 { | 1373 { |