Mercurial > vim
comparison src/vim9type.c @ 24160:e695db9a5465 v8.2.2621
patch 8.2.2621: typval2type() cannot handle recursive structures
Commit: https://github.com/vim/vim/commit/108cf0153c5770e343aec9e2390acdaa4a0b149a
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Mar 18 22:15:04 2021 +0100
patch 8.2.2621: typval2type() cannot handle recursive structures
Problem: typval2type() cannot handle recursive structures.
Solution: Use copyID. (closes https://github.com/vim/vim/issues/7979)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 18 Mar 2021 22:30:03 +0100 |
parents | 1027495445bc |
children | 5c6ccab68d1e |
comparison
equal
deleted
inserted
replaced
24159:f2c1bf894535 | 24160:e695db9a5465 |
---|---|
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 */ | 255 */ |
256 static type_T * | 256 static type_T * |
257 typval2type_int(typval_T *tv, garray_T *type_gap) | 257 typval2type_int(typval_T *tv, int copyID, garray_T *type_gap) |
258 { | 258 { |
259 type_T *type; | 259 type_T *type; |
260 type_T *member_type = &t_any; | 260 type_T *member_type = &t_any; |
261 int argcount = 0; | 261 int argcount = 0; |
262 | 262 |
274 | 274 |
275 if (l == NULL || l->lv_first == NULL) | 275 if (l == NULL || l->lv_first == NULL) |
276 return &t_list_empty; | 276 return &t_list_empty; |
277 if (l->lv_first == &range_list_item) | 277 if (l->lv_first == &range_list_item) |
278 return &t_list_number; | 278 return &t_list_number; |
279 if (l->lv_copyID == copyID) | |
280 // avoid recursion | |
281 return &t_list_any; | |
282 l->lv_copyID = copyID; | |
279 | 283 |
280 // Use the common type of all members. | 284 // Use the common type of all members. |
281 member_type = typval2type(&l->lv_first->li_tv, type_gap); | 285 member_type = typval2type(&l->lv_first->li_tv, copyID, type_gap); |
282 for (li = l->lv_first->li_next; li != NULL; li = li->li_next) | 286 for (li = l->lv_first->li_next; li != NULL; li = li->li_next) |
283 common_type(typval2type(&li->li_tv, type_gap), | 287 common_type(typval2type(&li->li_tv, copyID, type_gap), |
284 member_type, &member_type, type_gap); | 288 member_type, &member_type, type_gap); |
285 return get_list_type(member_type, type_gap); | 289 return get_list_type(member_type, type_gap); |
286 } | 290 } |
287 | 291 |
288 if (tv->v_type == VAR_DICT) | 292 if (tv->v_type == VAR_DICT) |
289 { | 293 { |
290 dict_iterator_T iter; | 294 dict_iterator_T iter; |
291 typval_T *value; | 295 typval_T *value; |
292 | 296 dict_T *d = tv->vval.v_dict; |
293 if (tv->vval.v_dict == NULL | 297 |
294 || tv->vval.v_dict->dv_hashtab.ht_used == 0) | 298 if (d == NULL || d->dv_hashtab.ht_used == 0) |
295 return &t_dict_empty; | 299 return &t_dict_empty; |
300 if (d->dv_copyID == copyID) | |
301 // avoid recursion | |
302 return &t_dict_any; | |
303 d->dv_copyID = copyID; | |
296 | 304 |
297 // Use the common type of all values. | 305 // Use the common type of all values. |
298 dict_iterate_start(tv, &iter); | 306 dict_iterate_start(tv, &iter); |
299 dict_iterate_next(&iter, &value); | 307 dict_iterate_next(&iter, &value); |
300 member_type = typval2type(value, type_gap); | 308 member_type = typval2type(value, copyID, type_gap); |
301 while (dict_iterate_next(&iter, &value) != NULL) | 309 while (dict_iterate_next(&iter, &value) != NULL) |
302 common_type(typval2type(value, type_gap), | 310 common_type(typval2type(value, copyID, type_gap), |
303 member_type, &member_type, type_gap); | 311 member_type, &member_type, type_gap); |
304 return get_dict_type(member_type, type_gap); | 312 return get_dict_type(member_type, type_gap); |
305 } | 313 } |
306 | 314 |
307 if (tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) | 315 if (tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) |
370 /* | 378 /* |
371 * Get a type_T for a typval_T. | 379 * Get a type_T for a typval_T. |
372 * "type_list" is used to temporarily create types in. | 380 * "type_list" is used to temporarily create types in. |
373 */ | 381 */ |
374 type_T * | 382 type_T * |
375 typval2type(typval_T *tv, garray_T *type_gap) | 383 typval2type(typval_T *tv, int copyID, garray_T *type_gap) |
376 { | 384 { |
377 type_T *type = typval2type_int(tv, type_gap); | 385 type_T *type = typval2type_int(tv, copyID, type_gap); |
378 | 386 |
379 if (type != NULL && type != &t_bool | 387 if (type != NULL && type != &t_bool |
380 && (tv->v_type == VAR_NUMBER | 388 && (tv->v_type == VAR_NUMBER |
381 && (tv->vval.v_number == 0 || tv->vval.v_number == 1))) | 389 && (tv->vval.v_number == 0 || tv->vval.v_number == 1))) |
382 // Number 0 and 1 and expression with "&&" or "||" can also be used for | 390 // Number 0 and 1 and expression with "&&" or "||" can also be used for |
394 { | 402 { |
395 if (tv->v_type == VAR_LIST) // e.g. for v:oldfiles | 403 if (tv->v_type == VAR_LIST) // e.g. for v:oldfiles |
396 return &t_list_string; | 404 return &t_list_string; |
397 if (tv->v_type == VAR_DICT) // e.g. for v:completed_item | 405 if (tv->v_type == VAR_DICT) // e.g. for v:completed_item |
398 return &t_dict_any; | 406 return &t_dict_any; |
399 return typval2type(tv, type_gap); | 407 return typval2type(tv, get_copyID(), type_gap); |
400 } | 408 } |
401 | 409 |
402 int | 410 int |
403 check_typval_arg_type(type_T *expected, typval_T *actual_tv, int arg_idx) | 411 check_typval_arg_type(type_T *expected, typval_T *actual_tv, int arg_idx) |
404 { | 412 { |
419 garray_T type_list; | 427 garray_T type_list; |
420 type_T *actual_type; | 428 type_T *actual_type; |
421 int res = FAIL; | 429 int res = FAIL; |
422 | 430 |
423 ga_init2(&type_list, sizeof(type_T *), 10); | 431 ga_init2(&type_list, sizeof(type_T *), 10); |
424 actual_type = typval2type(actual_tv, &type_list); | 432 actual_type = typval2type(actual_tv, get_copyID(), &type_list); |
425 if (actual_type != NULL) | 433 if (actual_type != NULL) |
426 res = check_type(expected, actual_type, TRUE, where); | 434 res = check_type(expected, actual_type, TRUE, where); |
427 clear_type_list(&type_list); | 435 clear_type_list(&type_list); |
428 return res; | 436 return res; |
429 } | 437 } |
1200 char *tofree; | 1208 char *tofree; |
1201 char *name; | 1209 char *name; |
1202 | 1210 |
1203 rettv->v_type = VAR_STRING; | 1211 rettv->v_type = VAR_STRING; |
1204 ga_init2(&type_list, sizeof(type_T *), 10); | 1212 ga_init2(&type_list, sizeof(type_T *), 10); |
1205 type = typval2type(argvars, &type_list); | 1213 type = typval2type(argvars, get_copyID(), &type_list); |
1206 name = type_name(type, &tofree); | 1214 name = type_name(type, &tofree); |
1207 if (tofree != NULL) | 1215 if (tofree != NULL) |
1208 rettv->vval.v_string = (char_u *)tofree; | 1216 rettv->vval.v_string = (char_u *)tofree; |
1209 else | 1217 else |
1210 { | 1218 { |