diff src/vim9compile.c @ 22284:6b385c2b9ff5 v8.2.1691

patch 8.2.1691: Vim9: list<any> is not accepted where list<number> is expected Commit: https://github.com/vim/vim/commit/5e654230777ad21363a929dce3cfe0387da031a7 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Sep 16 15:22:00 2020 +0200 patch 8.2.1691: Vim9: list<any> is not accepted where list<number> is expected Problem: Vim9: list<any> is not accepted where list<number> is expected. Solution: Add functions to allocate and free a type_T, use it in ISN_CHECKTYPE. (closes #6959)
author Bram Moolenaar <Bram@vim.org>
date Wed, 16 Sep 2020 15:30:07 +0200
parents 753452747ae5
children 3515f341e8ac
line wrap: on
line diff
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -704,7 +704,10 @@ generate_2BOOL(cctx_T *cctx, int invert)
 }
 
     static int
-generate_TYPECHECK(cctx_T *cctx, type_T *vartype, int offset)
+generate_TYPECHECK(
+	cctx_T	    *cctx,
+	type_T	    *expected,
+	int	    offset)
 {
     isn_T	*isn;
     garray_T	*stack = &cctx->ctx_type_stack;
@@ -712,19 +715,18 @@ generate_TYPECHECK(cctx_T *cctx, type_T 
     RETURN_OK_IF_SKIP(cctx);
     if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL)
 	return FAIL;
-    // TODO: whole type, e.g. for a function also arg and return types
-    isn->isn_arg.type.ct_type = vartype->tt_type;
+    isn->isn_arg.type.ct_type = alloc_type(expected);
     isn->isn_arg.type.ct_off = offset;
 
-    // type becomes vartype
-    ((type_T **)stack->ga_data)[stack->ga_len + offset] = vartype;
+    // type becomes expected
+    ((type_T **)stack->ga_data)[stack->ga_len + offset] = expected;
 
     return OK;
 }
 
 /*
  * Check that
- * - "actual" is "expected" type or
+ * - "actual" matches "expected" type or
  * - "actual" is a type that can be "expected" type: add a runtime check; or
  * - return FAIL.
  */
@@ -747,17 +749,29 @@ need_type(
 
     if (check_type(expected, actual, FALSE, 0) == OK)
 	return OK;
-    if (actual->tt_type != VAR_ANY
-	    && actual->tt_type != VAR_UNKNOWN
-	    && !(actual->tt_type == VAR_FUNC
-		&& (actual->tt_member == &t_any || actual->tt_argcount < 0)))
-    {
-	if (!silent)
-	    type_mismatch(expected, actual);
-	return FAIL;
-    }
-    generate_TYPECHECK(cctx, expected, offset);
-    return OK;
+
+    // If the actual type can be the expected type add a runtime check.
+    // TODO: if it's a constant a runtime check makes no sense.
+    if (actual->tt_type == VAR_ANY
+	    || actual->tt_type == VAR_UNKNOWN
+	    || (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_type == VAR_LIST
+		&& expected->tt_type == VAR_LIST
+		&& actual->tt_member == &t_any)
+	    || (actual->tt_type == VAR_DICT
+		&& expected->tt_type == VAR_DICT
+		&& actual->tt_member == &t_any))
+    {
+	generate_TYPECHECK(cctx, expected, offset);
+	return OK;
+    }
+
+    if (!silent)
+	type_mismatch(expected, actual);
+    return FAIL;
 }
 
 /*
@@ -776,7 +790,7 @@ generate_PUSHNR(cctx_T *cctx, varnumber_
 
     if (number == 0 || number == 1)
     {
-	type_T	*type = alloc_type(cctx->ctx_type_list);
+	type_T	*type = get_type_ptr(cctx->ctx_type_list);
 
 	// A 0 or 1 number can also be used as a bool.
 	if (type != NULL)
@@ -4037,7 +4051,7 @@ compile_and_or(
 	typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
 	if (*typep != &t_bool)
 	{
-	    type_T *type = alloc_type(cctx->ctx_type_list);
+	    type_T *type = get_type_ptr(cctx->ctx_type_list);
 
 	    if (type != NULL)
 	    {
@@ -7290,6 +7304,10 @@ delete_instr(isn_T *isn)
 	    }
 	    break;
 
+	case ISN_CHECKTYPE:
+	    free_type(isn->isn_arg.type.ct_type);
+	    break;
+
 	case ISN_2BOOL:
 	case ISN_2STRING:
 	case ISN_2STRING_ANY:
@@ -7301,7 +7319,6 @@ delete_instr(isn_T *isn)
 	case ISN_CATCH:
 	case ISN_CHECKLEN:
 	case ISN_CHECKNR:
-	case ISN_CHECKTYPE:
 	case ISN_COMPAREANY:
 	case ISN_COMPAREBLOB:
 	case ISN_COMPAREBOOL: