Patch 8.2.3869
Problem:    Vim9: type checking for "any" is inconsistent.
Solution:   Always use a runtime type check for using "any" for a more
            specific type.
Files:      src/vim9type.c, src/vim9compile.c, src/vim9expr.c,
            src/testdir/test_vim9_func.vim


*** ../vim-8.2.3868/src/vim9type.c      2021-12-21 13:30:38.732749872 +0000
--- src/vim9type.c      2021-12-22 13:08:44.653775876 +0000
***************
*** 477,483 ****
      ga_init2(&type_list, sizeof(type_T *), 10);
      actual_type = typval2type(actual_tv, get_copyID(), &type_list, TRUE);
      if (actual_type != NULL)
!       res = check_type(expected, actual_type, TRUE, where);
      clear_type_list(&type_list);
      return res;
  }
--- 477,495 ----
      ga_init2(&type_list, sizeof(type_T *), 10);
      actual_type = typval2type(actual_tv, get_copyID(), &type_list, TRUE);
      if (actual_type != NULL)
!     {
!       res = check_type_maybe(expected, actual_type, TRUE, where);
!       if (res == MAYBE && !(actual_type->tt_type == VAR_FUNC
!                                     && actual_type->tt_member == &t_unknown))
!       {
!           // If a type check is needed that means assigning "any" or
!           // "unknown" to a more specific type, which fails here.
!           // Execpt when it looks like a lambda, since they have an
!           // incomplete type.
!           type_mismatch_where(expected, actual_type, where);
!           res = FAIL;
!       }
!     }
      clear_type_list(&type_list);
      return res;
  }
***************
*** 567,575 ****
      {
        // tt_type should match, except that a "partial" can be assigned to a
        // variable with type "func".
!       // And "unknown" (using global variable) needs a runtime type check.
        if (!(expected->tt_type == actual->tt_type
                    || actual->tt_type == VAR_UNKNOWN
                    || (expected->tt_type == VAR_FUNC
                                           && actual->tt_type == VAR_PARTIAL)))
        {
--- 579,589 ----
      {
        // tt_type should match, except that a "partial" can be assigned to a
        // variable with type "func".
!       // And "unknown" (using global variable) and "any" need a runtime type
!       // check.
        if (!(expected->tt_type == actual->tt_type
                    || actual->tt_type == VAR_UNKNOWN
+                   || actual->tt_type == VAR_ANY
                    || (expected->tt_type == VAR_FUNC
                                           && actual->tt_type == VAR_PARTIAL)))
        {
***************
*** 585,594 ****
        {
            // "unknown" is used for an empty list or dict
            if (actual->tt_member != NULL && actual->tt_member != &t_unknown)
!               ret = check_type(expected->tt_member, actual->tt_member,
                                                                 FALSE, where);
        }
!       else if (expected->tt_type == VAR_FUNC)
        {
            // If the return type is unknown it can be anything, including
            // nothing, thus there is no point in checking.
--- 599,608 ----
        {
            // "unknown" is used for an empty list or dict
            if (actual->tt_member != NULL && actual->tt_member != &t_unknown)
!               ret = check_type_maybe(expected->tt_member, actual->tt_member,
                                                                 FALSE, where);
        }
!       else if (expected->tt_type == VAR_FUNC && actual != &t_any)
        {
            // If the return type is unknown it can be anything, including
            // nothing, thus there is no point in checking.
***************
*** 596,603 ****
            {
                if (actual->tt_member != NULL
                                            && actual->tt_member != &t_unknown)
!                   ret = check_type(expected->tt_member, actual->tt_member,
!                                                                FALSE, where);
                else
                    ret = MAYBE;
            }
--- 610,617 ----
            {
                if (actual->tt_member != NULL
                                            && actual->tt_member != &t_unknown)
!                   ret = check_type_maybe(expected->tt_member,
!                                             actual->tt_member, FALSE, where);
                else
                    ret = MAYBE;
            }
*** ../vim-8.2.3868/src/vim9compile.c   2021-12-20 15:03:23.247346527 +0000
--- src/vim9compile.c   2021-12-22 10:23:22.215274437 +0000
***************
*** 366,373 ****
            || (actual->tt_type == VAR_FUNC
                && (expected->tt_type == VAR_FUNC
                                           || expected->tt_type == VAR_PARTIAL)
!               && (actual->tt_member == &t_any || actual->tt_argcount < 0)
!               && ((actual->tt_member == &t_void)
                                         == (expected->tt_member == &t_void))))
        return TRUE;
      if ((actual->tt_type == VAR_LIST || actual->tt_type == VAR_DICT)
--- 366,376 ----
            || (actual->tt_type == VAR_FUNC
                && (expected->tt_type == VAR_FUNC
                                           || expected->tt_type == VAR_PARTIAL)
!               && (actual->tt_member == &t_any
!                   || actual->tt_member == &t_unknown
!                   || actual->tt_argcount < 0)
!               && (actual->tt_member == &t_unknown ||
!                   (actual->tt_member == &t_void)
                                         == (expected->tt_member == &t_void))))
        return TRUE;
      if ((actual->tt_type == VAR_LIST || actual->tt_type == VAR_DICT)
***************
*** 412,419 ****
  
      // If the actual type can be the expected type add a runtime check.
      // If it's a constant a runtime check makes no sense.
!     if (ret == MAYBE || ((!actual_is_const || actual == &t_any)
!                                          && use_typecheck(actual, expected)))
      {
        generate_TYPECHECK(cctx, expected, offset, where.wt_index);
        return OK;
--- 415,421 ----
  
      // If the actual type can be the expected type add a runtime check.
      // If it's a constant a runtime check makes no sense.
!     if (!actual_is_const && ret == MAYBE && use_typecheck(actual, expected))
      {
        generate_TYPECHECK(cctx, expected, offset, where.wt_index);
        return OK;
***************
*** 2547,2554 ****
                did_set_arg_type = TRUE;
                ufunc->uf_arg_types[arg_idx] = val_type;
            }
!           else if (check_type(ufunc->uf_arg_types[arg_idx], val_type,
!                                                         TRUE, where) == FAIL)
                goto erret;
  
            if (generate_STORE(&cctx, ISN_STORE, i - count - off, NULL) == FAIL)
--- 2549,2556 ----
                did_set_arg_type = TRUE;
                ufunc->uf_arg_types[arg_idx] = val_type;
            }
!           else if (need_type_where(val_type, ufunc->uf_arg_types[arg_idx],
!                                      -1, where, &cctx, FALSE, FALSE) == FAIL)
                goto erret;
  
            if (generate_STORE(&cctx, ISN_STORE, i - count - off, NULL) == FAIL)
*** ../vim-8.2.3868/src/vim9expr.c      2021-12-21 12:32:13.296529989 +0000
--- src/vim9expr.c      2021-12-22 12:54:15.358305817 +0000
***************
*** 415,421 ****
                // Global, Buffer-local, Window-local and Tabpage-local
                // variables can be defined later, thus we don't check if it
                // exists, give an error at runtime.
!               res = generate_LOAD(cctx, isn_type, 0, name, &t_unknown);
            }
        }
      }
--- 415,421 ----
                // Global, Buffer-local, Window-local and Tabpage-local
                // variables can be defined later, thus we don't check if it
                // exists, give an error at runtime.
!               res = generate_LOAD(cctx, isn_type, 0, name, &t_any);
            }
        }
      }
***************
*** 2846,2851 ****
--- 2846,2852 ----
            type_T      **typep;
  
            generate_ppconst(cctx, ppconst);
+           ppconst->pp_is_const = FALSE;
  
            // If the types differ, the result has a more generic type.
            typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
*** ../vim-8.2.3868/src/testdir/test_vim9_func.vim      2021-12-21 
12:32:13.300529985 +0000
--- src/testdir/test_vim9_func.vim      2021-12-22 12:39:26.895411887 +0000
***************
*** 548,554 ****
    END
    CheckScriptFailure(lines, 'E1001: Variable not found: b')
  
!   # using script variable requires matching type or type cast
    lines =<< trim END
        vim9script
        var a: any
--- 548,554 ----
    END
    CheckScriptFailure(lines, 'E1001: Variable not found: b')
  
!   # using script variable requires matching type or type cast when executed
    lines =<< trim END
        vim9script
        var a: any
***************
*** 557,574 ****
        enddef
        defcompile
    END
!   CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected 
string but got any')
! 
!   lines =<< trim END
!       vim9script
!       var a: any
!       def Func(arg: string = <string>a)
!         echo arg
!       enddef
!       a = 'works'
!       Func()
!   END
!   CheckScriptSuccess(lines)
  
    # using global variable does not require type cast
    lines =<< trim END
--- 557,564 ----
        enddef
        defcompile
    END
!   CheckScriptSuccess(lines + ['a = "text"', 'Func()'])
!   CheckScriptFailure(lines + ['a = 123', 'Func()'], 'E1013: Argument 1: type 
mismatch, expected string but got number')
  
    # using global variable does not require type cast
    lines =<< trim END
*** ../vim-8.2.3868/src/version.c       2021-12-21 13:30:38.736749839 +0000
--- src/version.c       2021-12-22 09:57:23.547319519 +0000
***************
*** 751,752 ****
--- 751,754 ----
  {   /* Add new patch number below this line */
+ /**/
+     3869,
  /**/

-- 
Warning label on a superhero Halloween costume:
"Caution: Cape does not enable user to fly."

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20211222131910.7B39B1C0641%40moolenaar.net.

Raspunde prin e-mail lui