Mercurial > vim
comparison src/vim9type.c @ 34987:4eeeba47eb0a v9.1.0349
patch 9.1.0349: Vim9: need static type for typealias
Commit: https://github.com/vim/vim/commit/76ba252e6192580d22737708d69dad7c777fb68a
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Thu Apr 18 21:33:27 2024 +0200
patch 9.1.0349: Vim9: need static type for typealias
Problem: Vim9: need static type for typealias
Solution: Refactor the typval2type() function and add a static type for
typealias (Yegappan Lakshmanan)
closes: #14582
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Thu, 18 Apr 2024 21:45:03 +0200 |
parents | 3f9d9ee5cb7c |
children | 6dca41acb99c |
comparison
equal
deleted
inserted
replaced
34986:db6202f2c210 | 34987:4eeeba47eb0a |
---|---|
416 return type == NULL || type->tt_type == VAR_ANY | 416 return type == NULL || type->tt_type == VAR_ANY |
417 || type->tt_type == VAR_UNKNOWN; | 417 || type->tt_type == VAR_UNKNOWN; |
418 } | 418 } |
419 | 419 |
420 /* | 420 /* |
421 * Get a type_T for a partial typval in "tv". | 421 * Get a type_T for a "special" typval in "tv". |
422 */ | |
423 static type_T * | |
424 special_typval2type(typval_T *tv) | |
425 { | |
426 switch (tv->vval.v_number) | |
427 { | |
428 case VVAL_NULL: | |
429 return &t_null; | |
430 | |
431 case VVAL_NONE: | |
432 return &t_none; | |
433 | |
434 case VVAL_TRUE: | |
435 case VVAL_FALSE: | |
436 return &t_bool; | |
437 | |
438 default: | |
439 return &t_unknown; | |
440 } | |
441 } | |
442 | |
443 /* | |
444 * Get a type_T for a List typval in "tv". | |
445 * When "flags" has TVTT_DO_MEMBER also get the member type, otherwise use | |
446 * "any". | |
447 * When "flags" has TVTT_MORE_SPECIFIC get the more specific member type if it | |
448 * is "any". | |
449 */ | |
450 static type_T * | |
451 list_typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags) | |
452 { | |
453 list_T *l = tv->vval.v_list; | |
454 listitem_T *li; | |
455 type_T *member_type = NULL; | |
456 | |
457 // An empty list has type list<unknown>, unless the type was specified | |
458 // and is not list<any>. This matters when assigning to a variable | |
459 // with a specific list type. | |
460 if (l == NULL || (l->lv_first == NULL | |
461 && (l->lv_type == NULL || l->lv_type->tt_member == &t_any))) | |
462 return &t_list_empty; | |
463 | |
464 if ((flags & TVTT_DO_MEMBER) == 0) | |
465 return &t_list_any; | |
466 | |
467 // If the type is list<any> go through the members, it may end up a | |
468 // more specific type. | |
469 if (l->lv_type != NULL && (l->lv_first == NULL | |
470 || (flags & TVTT_MORE_SPECIFIC) == 0 | |
471 || l->lv_type->tt_member != &t_any)) | |
472 // make a copy, lv_type may be freed if the list is freed | |
473 return copy_type_deep(l->lv_type, type_gap); | |
474 | |
475 if (l->lv_first == &range_list_item) | |
476 return &t_list_number; | |
477 | |
478 if (l->lv_copyID == copyID) | |
479 // avoid recursion | |
480 return &t_list_any; | |
481 | |
482 l->lv_copyID = copyID; | |
483 | |
484 // Use the common type of all members. | |
485 member_type = typval2type(&l->lv_first->li_tv, copyID, type_gap, | |
486 TVTT_DO_MEMBER); | |
487 for (li = l->lv_first->li_next; li != NULL; li = li->li_next) | |
488 common_type(typval2type(&li->li_tv, copyID, type_gap, TVTT_DO_MEMBER), | |
489 member_type, &member_type, type_gap); | |
490 | |
491 return get_list_type(member_type, type_gap); | |
492 } | |
493 | |
494 /* | |
495 * Get a type_T for a Dict typval in "tv". | |
496 * When "flags" has TVTT_DO_MEMBER also get the member type, otherwise use | |
497 * "any". | |
498 * When "flags" has TVTT_MORE_SPECIFIC get the more specific member type if it | |
499 * is "any". | |
500 */ | |
501 static type_T * | |
502 dict_typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags) | |
503 { | |
504 dict_iterator_T iter; | |
505 typval_T *value; | |
506 dict_T *d = tv->vval.v_dict; | |
507 type_T *member_type = NULL; | |
508 | |
509 if (d == NULL || (d->dv_hashtab.ht_used == 0 && d->dv_type == NULL)) | |
510 return &t_dict_empty; | |
511 | |
512 if ((flags & TVTT_DO_MEMBER) == 0) | |
513 return &t_dict_any; | |
514 | |
515 // If the type is dict<any> go through the members, it may end up a | |
516 // more specific type. | |
517 if (d->dv_type != NULL && (d->dv_hashtab.ht_used == 0 | |
518 || (flags & TVTT_MORE_SPECIFIC) == 0 | |
519 || d->dv_type->tt_member != &t_any)) | |
520 return d->dv_type; | |
521 | |
522 if (d->dv_copyID == copyID) | |
523 // avoid recursion | |
524 return &t_dict_any; | |
525 | |
526 d->dv_copyID = copyID; | |
527 | |
528 // Use the common type of all values. | |
529 dict_iterate_start(tv, &iter); | |
530 dict_iterate_next(&iter, &value); | |
531 member_type = typval2type(value, copyID, type_gap, TVTT_DO_MEMBER); | |
532 | |
533 while (dict_iterate_next(&iter, &value) != NULL) | |
534 common_type(typval2type(value, copyID, type_gap, TVTT_DO_MEMBER), | |
535 member_type, &member_type, type_gap); | |
536 | |
537 return get_dict_type(member_type, type_gap); | |
538 } | |
539 | |
540 /* | |
541 * Get a type_T for a "partial" typval in "tv". | |
422 */ | 542 */ |
423 static type_T * | 543 static type_T * |
424 partial_typval2type(typval_T *tv, ufunc_T *ufunc, garray_T *type_gap) | 544 partial_typval2type(typval_T *tv, ufunc_T *ufunc, garray_T *type_gap) |
425 { | 545 { |
426 partial_T *pt = tv->vval.v_partial; | 546 partial_T *pt = tv->vval.v_partial; |
446 | 566 |
447 return type; | 567 return type; |
448 } | 568 } |
449 | 569 |
450 /* | 570 /* |
451 * Get a type_T for a typval_T. | 571 * Get a type_T for a "class" or an "object" typval in "tv". |
452 * "type_gap" is used to temporarily create types in. | |
453 * When "flags" has TVTT_DO_MEMBER also get the member type, otherwise use | |
454 * "any". | |
455 * When "flags" has TVTT_MORE_SPECIFIC get the more specific member type if it | |
456 * is "any". | |
457 */ | 572 */ |
458 static type_T * | 573 static type_T * |
459 typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags) | 574 oc_typval2type(typval_T *tv) |
460 { | 575 { |
461 type_T *type; | 576 if (tv->v_type == VAR_CLASS) |
462 type_T *member_type = NULL; | 577 { |
463 class_T *class_type = NULL; | 578 if (tv->vval.v_class == NULL) |
464 int argcount = 0; | 579 return &t_class; |
465 int min_argcount = 0; | 580 |
466 | 581 return &tv->vval.v_class->class_type; |
467 if (tv->v_type == VAR_NUMBER) | 582 } |
468 return &t_number; | 583 |
469 if (tv->v_type == VAR_BOOL) | 584 if (tv->vval.v_object != NULL) |
470 return &t_bool; | 585 return &tv->vval.v_object->obj_class->class_object_type; |
471 if (tv->v_type == VAR_SPECIAL) | 586 |
472 { | 587 return &t_object; |
473 if (tv->vval.v_number == VVAL_NULL) | 588 } |
474 return &t_null; | 589 |
475 if (tv->vval.v_number == VVAL_NONE) | 590 /* |
476 return &t_none; | 591 * Get a type_T for a "function" or a "partial" |
477 if (tv->vval.v_number == VVAL_TRUE | 592 */ |
478 || tv->vval.v_number == VVAL_FALSE) | 593 static type_T * |
479 return &t_bool; | 594 fp_typval2type(typval_T *tv, garray_T *type_gap) |
480 return &t_unknown; | 595 { |
481 } | 596 char_u *name = NULL; |
482 if (tv->v_type == VAR_STRING) | 597 ufunc_T *ufunc = NULL; |
483 return &t_string; | 598 type_T *type; |
484 if (tv->v_type == VAR_BLOB) | 599 type_T *member_type = NULL; |
485 { | 600 int argcount = 0; |
486 if (tv->vval.v_blob == NULL) | 601 int min_argcount = 0; |
487 return &t_blob_null; | 602 |
488 return &t_blob; | 603 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL) |
489 } | 604 { |
490 | 605 if (tv->vval.v_partial->pt_func != NULL) |
491 if (tv->v_type == VAR_LIST) | 606 ufunc = tv->vval.v_partial->pt_func; |
492 { | |
493 list_T *l = tv->vval.v_list; | |
494 listitem_T *li; | |
495 | |
496 // An empty list has type list<unknown>, unless the type was specified | |
497 // and is not list<any>. This matters when assigning to a variable | |
498 // with a specific list type. | |
499 if (l == NULL || (l->lv_first == NULL | |
500 && (l->lv_type == NULL || l->lv_type->tt_member == &t_any))) | |
501 return &t_list_empty; | |
502 if ((flags & TVTT_DO_MEMBER) == 0) | |
503 return &t_list_any; | |
504 // If the type is list<any> go through the members, it may end up a | |
505 // more specific type. | |
506 if (l->lv_type != NULL && (l->lv_first == NULL | |
507 || (flags & TVTT_MORE_SPECIFIC) == 0 | |
508 || l->lv_type->tt_member != &t_any)) | |
509 // make a copy, lv_type may be freed if the list is freed | |
510 return copy_type_deep(l->lv_type, type_gap); | |
511 if (l->lv_first == &range_list_item) | |
512 return &t_list_number; | |
513 if (l->lv_copyID == copyID) | |
514 // avoid recursion | |
515 return &t_list_any; | |
516 l->lv_copyID = copyID; | |
517 | |
518 // Use the common type of all members. | |
519 member_type = typval2type(&l->lv_first->li_tv, copyID, type_gap, | |
520 TVTT_DO_MEMBER); | |
521 for (li = l->lv_first->li_next; li != NULL; li = li->li_next) | |
522 common_type(typval2type(&li->li_tv, copyID, type_gap, | |
523 TVTT_DO_MEMBER), | |
524 member_type, &member_type, type_gap); | |
525 return get_list_type(member_type, type_gap); | |
526 } | |
527 | |
528 if (tv->v_type == VAR_DICT) | |
529 { | |
530 dict_iterator_T iter; | |
531 typval_T *value; | |
532 dict_T *d = tv->vval.v_dict; | |
533 | |
534 if (d == NULL || (d->dv_hashtab.ht_used == 0 && d->dv_type == NULL)) | |
535 return &t_dict_empty; | |
536 if ((flags & TVTT_DO_MEMBER) == 0) | |
537 return &t_dict_any; | |
538 // If the type is dict<any> go through the members, it may end up a | |
539 // more specific type. | |
540 if (d->dv_type != NULL && (d->dv_hashtab.ht_used == 0 | |
541 || (flags & TVTT_MORE_SPECIFIC) == 0 | |
542 || d->dv_type->tt_member != &t_any)) | |
543 return d->dv_type; | |
544 if (d->dv_copyID == copyID) | |
545 // avoid recursion | |
546 return &t_dict_any; | |
547 d->dv_copyID = copyID; | |
548 | |
549 // Use the common type of all values. | |
550 dict_iterate_start(tv, &iter); | |
551 dict_iterate_next(&iter, &value); | |
552 member_type = typval2type(value, copyID, type_gap, TVTT_DO_MEMBER); | |
553 while (dict_iterate_next(&iter, &value) != NULL) | |
554 common_type(typval2type(value, copyID, type_gap, TVTT_DO_MEMBER), | |
555 member_type, &member_type, type_gap); | |
556 return get_dict_type(member_type, type_gap); | |
557 } | |
558 | |
559 if (tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) | |
560 { | |
561 char_u *name = NULL; | |
562 ufunc_T *ufunc = NULL; | |
563 | |
564 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL) | |
565 { | |
566 if (tv->vval.v_partial->pt_func != NULL) | |
567 ufunc = tv->vval.v_partial->pt_func; | |
568 else | |
569 name = tv->vval.v_partial->pt_name; | |
570 } | |
571 else | 607 else |
572 name = tv->vval.v_string; | 608 name = tv->vval.v_partial->pt_name; |
573 if (name == NULL && ufunc == NULL) | 609 } |
574 return &t_func_unknown; | 610 else |
575 if (name != NULL) | 611 name = tv->vval.v_string; |
576 { | 612 |
577 int idx = find_internal_func(name); | 613 if (name == NULL && ufunc == NULL) |
578 | 614 return &t_func_unknown; |
579 if (idx >= 0) | 615 |
580 { | 616 if (name != NULL) |
581 type_T *decl_type; // unused | 617 { |
582 | 618 int idx = find_internal_func(name); |
583 internal_func_get_argcount(idx, &argcount, &min_argcount); | 619 |
584 member_type = internal_func_ret_type(idx, 0, NULL, &decl_type, | 620 if (idx >= 0) |
585 type_gap); | 621 { |
586 } | 622 type_T *decl_type; // unused |
587 else | 623 |
588 ufunc = find_func(name, FALSE); | 624 internal_func_get_argcount(idx, &argcount, &min_argcount); |
589 } | 625 member_type = internal_func_ret_type(idx, 0, NULL, &decl_type, |
590 if (ufunc != NULL) | 626 type_gap); |
591 { | 627 } |
592 // May need to get the argument types from default values by | 628 else |
593 // compiling the function. | 629 ufunc = find_func(name, FALSE); |
594 if (ufunc->uf_def_status == UF_TO_BE_COMPILED | 630 } |
595 && compile_def_function(ufunc, TRUE, CT_NONE, NULL) | 631 if (ufunc != NULL) |
596 == FAIL) | 632 { |
597 return NULL; | 633 // May need to get the argument types from default values by |
598 if (ufunc->uf_func_type == NULL) | 634 // compiling the function. |
599 set_function_type(ufunc); | 635 if (ufunc->uf_def_status == UF_TO_BE_COMPILED |
600 if (ufunc->uf_func_type != NULL) | 636 && compile_def_function(ufunc, TRUE, CT_NONE, NULL) |
601 { | 637 == FAIL) |
602 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL) | 638 return NULL; |
603 return partial_typval2type(tv, ufunc, type_gap); | 639 if (ufunc->uf_func_type == NULL) |
604 return ufunc->uf_func_type; | 640 set_function_type(ufunc); |
605 } | 641 if (ufunc->uf_func_type != NULL) |
606 } | 642 { |
607 } | 643 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL) |
608 | 644 return partial_typval2type(tv, ufunc, type_gap); |
609 if (tv->v_type == VAR_CLASS) | 645 return ufunc->uf_func_type; |
610 class_type = tv->vval.v_class; | 646 } |
611 else if (tv->v_type == VAR_OBJECT && tv->vval.v_object != NULL) | 647 } |
612 class_type = tv->vval.v_object->obj_class; | |
613 | 648 |
614 type = get_type_ptr(type_gap); | 649 type = get_type_ptr(type_gap); |
615 if (type == NULL) | 650 if (type == NULL) |
616 return NULL; | 651 return NULL; |
617 type->tt_type = tv->v_type; | 652 type->tt_type = tv->v_type; |
618 type->tt_argcount = argcount; | 653 type->tt_argcount = argcount; |
619 type->tt_min_argcount = min_argcount; | 654 type->tt_min_argcount = min_argcount; |
620 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL | 655 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL |
621 && tv->vval.v_partial->pt_argc > 0) | 656 && tv->vval.v_partial->pt_argc > 0) |
622 { | 657 { |
623 type->tt_argcount -= tv->vval.v_partial->pt_argc; | 658 type->tt_argcount -= tv->vval.v_partial->pt_argc; |
624 type->tt_min_argcount -= tv->vval.v_partial->pt_argc; | 659 type->tt_min_argcount -= tv->vval.v_partial->pt_argc; |
625 } | 660 } |
626 type->tt_member = member_type; | 661 type->tt_member = member_type; |
627 type->tt_class = class_type; | |
628 | 662 |
629 return type; | 663 return type; |
664 } | |
665 | |
666 /* | |
667 * Get a type_T for a typval_T. | |
668 * "type_gap" is used to temporarily create types in. | |
669 * When "flags" has TVTT_DO_MEMBER also get the member type, otherwise use | |
670 * "any". | |
671 * When "flags" has TVTT_MORE_SPECIFIC get the more specific member type if it | |
672 * is "any". | |
673 */ | |
674 static type_T * | |
675 typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags) | |
676 { | |
677 switch (tv->v_type) | |
678 { | |
679 case VAR_UNKNOWN: | |
680 return &t_unknown; | |
681 | |
682 case VAR_ANY: | |
683 return &t_any; | |
684 | |
685 case VAR_VOID: | |
686 return &t_void; | |
687 | |
688 case VAR_BOOL: | |
689 return &t_bool; | |
690 | |
691 case VAR_SPECIAL: | |
692 return special_typval2type(tv); | |
693 | |
694 case VAR_NUMBER: | |
695 return &t_number; | |
696 | |
697 case VAR_FLOAT: | |
698 return &t_float; | |
699 | |
700 case VAR_STRING: | |
701 return &t_string; | |
702 | |
703 case VAR_BLOB: | |
704 if (tv->vval.v_blob == NULL) | |
705 return &t_blob_null; | |
706 return &t_blob; | |
707 | |
708 case VAR_LIST: | |
709 return list_typval2type(tv, copyID, type_gap, flags); | |
710 | |
711 case VAR_DICT: | |
712 return dict_typval2type(tv, copyID, type_gap, flags); | |
713 | |
714 case VAR_JOB: | |
715 return &t_job; | |
716 | |
717 case VAR_CHANNEL: | |
718 return &t_channel; | |
719 | |
720 case VAR_CLASS: | |
721 case VAR_OBJECT: | |
722 return oc_typval2type(tv); | |
723 | |
724 case VAR_TYPEALIAS: | |
725 return &t_typealias; | |
726 | |
727 case VAR_FUNC: | |
728 case VAR_PARTIAL: | |
729 return fp_typval2type(tv, type_gap); | |
730 | |
731 case VAR_INSTR: | |
732 default: | |
733 break; | |
734 } | |
735 | |
736 return NULL; | |
630 } | 737 } |
631 | 738 |
632 /* | 739 /* |
633 * Return TRUE if "tv" is not a bool but should be converted to bool. | 740 * Return TRUE if "tv" is not a bool but should be converted to bool. |
634 */ | 741 */ |