diff src/vim9expr.c @ 26935:ccb9be1cdd71 v8.2.3996

patch 8.2.3996: Vim9: type checking lacks information about declared type Commit: https://github.com/vim/vim/commit/078a46161e8b1b30bf306d6c1f4f0af7c616a989 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jan 4 15:17:03 2022 +0000 patch 8.2.3996: Vim9: type checking lacks information about declared type Problem: Vim9: type checking for list and dict lacks information about declared type. Solution: Add dv_decl_type and lv_decl_type. Refactor the type stack to store two types in each entry.
author Bram Moolenaar <Bram@vim.org>
date Tue, 04 Jan 2022 16:30:06 +0100
parents 612339679616
children 8796f1384750
line wrap: on
line diff
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -77,7 +77,7 @@ clear_ppconst(ppconst_T *ppconst)
     int
 compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
 {
-    type_T	**typep;
+    type2_T	*typep;
     garray_T	*stack = &cctx->ctx_type_stack;
     vartype_T	vartype;
     type_T	*idxtype;
@@ -85,12 +85,13 @@ compile_member(int is_slice, int *keepin
     // We can index a list, dict and blob.  If we don't know the type
     // we can use the index value type.  If we still don't know use an "ANY"
     // instruction.
-    typep = ((type_T **)stack->ga_data) + stack->ga_len
-						  - (is_slice ? 3 : 2);
-    vartype = (*typep)->tt_type;
-    idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+    // TODO: what about the decl type?
+    typep = (((type2_T *)stack->ga_data) + stack->ga_len - (is_slice ? 3 : 2));
+    vartype = typep->type_curr->tt_type;
+    idxtype = (((type2_T *)stack->ga_data) + stack->ga_len - 1)->type_curr;
     // If the index is a string, the variable must be a Dict.
-    if ((*typep == &t_any || *typep == &t_unknown) && idxtype == &t_string)
+    if ((typep->type_curr == &t_any || typep->type_curr == &t_unknown)
+						       && idxtype == &t_string)
 	vartype = VAR_DICT;
     if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB)
     {
@@ -98,7 +99,7 @@ compile_member(int is_slice, int *keepin
 	    return FAIL;
 	if (is_slice)
 	{
-	    idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
+	    idxtype = get_type_on_stack(cctx, 1);
 	    if (need_type(idxtype, &t_number, -2, 0, cctx,
 							 FALSE, FALSE) == FAIL)
 		return FAIL;
@@ -112,19 +113,29 @@ compile_member(int is_slice, int *keepin
 	    emsg(_(e_cannot_slice_dictionary));
 	    return FAIL;
 	}
-	if ((*typep)->tt_type == VAR_DICT)
+	if (typep->type_curr->tt_type == VAR_DICT)
 	{
-	    *typep = (*typep)->tt_member;
-	    if (*typep == &t_unknown)
+	    typep->type_curr = typep->type_curr->tt_member;
+	    if (typep->type_curr == &t_unknown)
 		// empty dict was used
-		*typep = &t_any;
+		typep->type_curr = &t_any;
+	    if (typep->type_decl->tt_type == VAR_DICT)
+	    {
+		typep->type_decl = typep->type_decl->tt_member;
+		if (typep->type_decl == &t_unknown)
+		    // empty dict was used
+		    typep->type_decl = &t_any;
+	    }
+	    else
+		typep->type_decl = typep->type_curr;
 	}
 	else
 	{
-	    if (need_type(*typep, &t_dict_any, -2, 0, cctx,
+	    if (need_type(typep->type_curr, &t_dict_any, -2, 0, cctx,
 							 FALSE, FALSE) == FAIL)
 		return FAIL;
-	    *typep = &t_any;
+	    typep->type_curr = &t_any;
+	    typep->type_decl = &t_any;
 	}
 	if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
 	    return FAIL;
@@ -135,7 +146,8 @@ compile_member(int is_slice, int *keepin
     }
     else if (vartype == VAR_STRING)
     {
-	*typep = &t_string;
+	typep->type_curr = &t_string;
+	typep->type_decl = &t_string;
 	if ((is_slice
 		? generate_instr_drop(cctx, ISN_STRSLICE, 2)
 		: generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL)
@@ -145,18 +157,21 @@ compile_member(int is_slice, int *keepin
     {
 	if (is_slice)
 	{
-	    *typep = &t_blob;
+	    typep->type_curr = &t_blob;
+	    typep->type_decl = &t_blob;
 	    if (generate_instr_drop(cctx, ISN_BLOBSLICE, 2) == FAIL)
 		return FAIL;
 	}
 	else
 	{
-	    *typep = &t_number;
+	    typep->type_curr = &t_number;
+	    typep->type_decl = &t_number;
 	    if (generate_instr_drop(cctx, ISN_BLOBINDEX, 1) == FAIL)
 		return FAIL;
 	}
     }
-    else if (vartype == VAR_LIST || *typep == &t_any || *typep == &t_unknown)
+    else if (vartype == VAR_LIST || typep->type_curr == &t_any
+					     || typep->type_curr == &t_unknown)
     {
 	if (is_slice)
 	{
@@ -167,12 +182,21 @@ compile_member(int is_slice, int *keepin
 	}
 	else
 	{
-	    if ((*typep)->tt_type == VAR_LIST)
+	    if (typep->type_curr->tt_type == VAR_LIST)
 	    {
-		*typep = (*typep)->tt_member;
-		if (*typep == &t_unknown)
+		typep->type_curr = typep->type_curr->tt_member;
+		if (typep->type_curr == &t_unknown)
 		    // empty list was used
-		    *typep = &t_any;
+		    typep->type_curr = &t_any;
+		if (typep->type_decl->tt_type == VAR_LIST)
+		{
+		    typep->type_decl = typep->type_decl->tt_member;
+		    if (typep->type_decl == &t_unknown)
+			// empty list was used
+			typep->type_decl = &t_any;
+		}
+		else
+			typep->type_decl = typep->type_curr;
 	    }
 	    if (generate_instr_drop(cctx,
 			vartype == VAR_LIST ?  ISN_LISTINDEX : ISN_ANYINDEX, 1)
@@ -709,9 +733,7 @@ compile_call(
 
 	    if (STRCMP(name, "add") == 0 && argcount == 2)
 	    {
-		garray_T    *stack = &cctx->ctx_type_stack;
-		type_T	    *type = ((type_T **)stack->ga_data)[
-							    stack->ga_len - 2];
+		type_T	    *type = get_type_on_stack(cctx, 1);
 
 		// add() can be compiled to instructions if we know the type
 		if (type->tt_type == VAR_LIST)
@@ -758,8 +780,7 @@ compile_call(
     if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload
 	    && compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK)
     {
-	garray_T    *stack = &cctx->ctx_type_stack;
-	type_T	    *type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+	type_T	    *type = get_type_on_stack(cctx, 0);
 
 	res = generate_PCALL(cctx, argcount, namebuf, type, FALSE);
 	goto theend;
@@ -1421,10 +1442,9 @@ skip_expr_cctx(char_u **arg, cctx_T *cct
     int
 bool_on_stack(cctx_T *cctx)
 {
-    garray_T	*stack = &cctx->ctx_type_stack;
     type_T	*type;
 
-    type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+    type = get_type_on_stack(cctx, 0);
     if (type == &t_bool)
 	return OK;
 
@@ -1470,10 +1490,9 @@ compile_leader(cctx_T *cctx, int numeric
 	{
 	    int		negate = *p == '-';
 	    isn_T	*isn;
-	    garray_T    *stack = &cctx->ctx_type_stack;
 	    type_T	*type;
 
-	    type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+	    type = get_type_on_stack(cctx, 0);
 	    if (type != &t_float && need_type(type, &t_number,
 					    -1, 0, cctx, FALSE, FALSE) == FAIL)
 		return FAIL;
@@ -1594,7 +1613,6 @@ compile_subscript(
 	// is not a function call.
 	if (**arg == '(')
 	{
-	    garray_T    *stack = &cctx->ctx_type_stack;
 	    type_T	*type;
 	    int		argcount = 0;
 
@@ -1603,7 +1621,7 @@ compile_subscript(
 	    ppconst->pp_is_const = FALSE;
 
 	    // funcref(arg)
-	    type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+	    type = get_type_on_stack(cctx, 0);
 
 	    *arg = skipwhite(p + 1);
 	    if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
@@ -1672,12 +1690,13 @@ compile_subscript(
 		// instructions of the expression and move the type of the
 		// expression after the argument types.  This is what ISN_PCALL
 		// expects.
-		stack = &cctx->ctx_type_stack;
 		arg_isn_count = cctx->ctx_instr.ga_len - expr_isn_end;
 		if (arg_isn_count > 0)
 		{
 		    int	    expr_isn_count = expr_isn_end - expr_isn_start;
 		    isn_T   *isn = ALLOC_MULT(isn_T, expr_isn_count);
+		    type_T  *decl_type;
+		    type2_T  *typep;
 
 		    if (isn == NULL)
 			return FAIL;
@@ -1693,15 +1712,19 @@ compile_subscript(
 					  isn, sizeof(isn_T) * expr_isn_count);
 		    vim_free(isn);
 
-		    type = ((type_T **)stack->ga_data)[type_idx_start];
-		    mch_memmove(((type_T **)stack->ga_data) + type_idx_start,
-			      ((type_T **)stack->ga_data) + type_idx_start + 1,
-			      sizeof(type_T *)
+		    typep = ((type2_T *)stack->ga_data) + type_idx_start;
+		    type = typep->type_curr;
+		    decl_type = typep->type_decl;
+		    mch_memmove(((type2_T *)stack->ga_data) + type_idx_start,
+			      ((type2_T *)stack->ga_data) + type_idx_start + 1,
+			      sizeof(type2_T)
 				       * (stack->ga_len - type_idx_start - 1));
-		    ((type_T **)stack->ga_data)[stack->ga_len - 1] = type;
+		    typep = ((type2_T *)stack->ga_data) + stack->ga_len - 1;
+		    typep->type_curr = type;
+		    typep->type_decl = decl_type;
 		}
 
-		type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+		type = get_type_on_stack(cctx, 0);
 		if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL)
 		    return FAIL;
 	    }
@@ -2152,12 +2175,11 @@ compile_expr7(char_u **arg, cctx_T *cctx
 
     if (want_type != NULL)
     {
-	garray_T    *stack = &cctx->ctx_type_stack;
 	type_T	    *actual;
 	where_T	    where = WHERE_INIT;
 
 	generate_ppconst(cctx, ppconst);
-	actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+	actual = get_type_on_stack(cctx, 0);
 	if (check_type_maybe(want_type, actual, FALSE, where) != OK)
 	{
 	    if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE)
@@ -2781,7 +2803,7 @@ compile_expr1(char_u **arg, cctx_T *cctx
 	    generate_JUMP(cctx, op_falsy
 				   ? JUMP_AND_KEEP_IF_TRUE : JUMP_IF_FALSE, 0);
 	    if (op_falsy)
-		type1 = ((type_T **)stack->ga_data)[stack->ga_len];
+		type1 = get_type_on_stack(cctx, -1);
 	}
 
 	// evaluate the second expression; any type is accepted
@@ -2797,8 +2819,8 @@ compile_expr1(char_u **arg, cctx_T *cctx
 	    if (!op_falsy)
 	    {
 		// remember the type and drop it
+		type1 = get_type_on_stack(cctx, 0);
 		--stack->ga_len;
-		type1 = ((type_T **)stack->ga_data)[stack->ga_len];
 
 		end_idx = instr->ga_len;
 		generate_JUMP(cctx, JUMP_ALWAYS, 0);
@@ -2849,7 +2871,8 @@ compile_expr1(char_u **arg, cctx_T *cctx
 	    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;
+	    typep = &((((type2_T *)stack->ga_data)
+					      + stack->ga_len - 1)->type_curr);
 	    common_type(type1, *typep, typep, cctx->ctx_type_list);
 
 	    // jump here from JUMP_ALWAYS or JUMP_AND_KEEP_IF_TRUE