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 {