diff src/eval.c @ 323:03b3684919e3 v7.0084

updated for version 7.0084
author vimboss
date Mon, 13 Jun 2005 22:28:56 +0000
parents a0451524244d
children bfd8935d6200
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -264,12 +264,11 @@ typedef struct
 #define VV_RO		2	/* read-only */
 #define VV_RO_SBX	4	/* read-only in the sandbox */
 
-#define VV_NAME(s, t)	s, sizeof(s) - 1, {{t}}, {0}
+#define VV_NAME(s, t)	s, {{t}}, {0}
 
 static struct vimvar
 {
     char	*vv_name;	/* name of variable, without v: */
-    int		vv_len;		/* length of name */
     dictitem_T	vv_di;		/* value and name for key */
     char	vv_filler[16];	/* space for LONGEST name below!!! */
     char	vv_flags;	/* VV_COMPAT, VV_RO, VV_RO_SBX */
@@ -594,9 +593,12 @@ static void free_tv __ARGS((typval_T *va
 static void clear_tv __ARGS((typval_T *varp));
 static void init_tv __ARGS((typval_T *varp));
 static long get_tv_number __ARGS((typval_T *varp));
+static long get_tv_number_chk __ARGS((typval_T *varp, int *denote));
 static linenr_T get_tv_lnum __ARGS((typval_T *argvars));
 static char_u *get_tv_string __ARGS((typval_T *varp));
+static char_u *get_tv_string_chk __ARGS((typval_T *varp));
 static char_u *get_tv_string_buf __ARGS((typval_T *varp, char_u *buf));
+static char_u *get_tv_string_buf_chk __ARGS((typval_T *varp, char_u *buf));
 static dictitem_T *find_var __ARGS((char_u *name, hashtab_T **htp));
 static dictitem_T *find_var_in_ht __ARGS((hashtab_T *ht, char_u *varname, int writing));
 static hashtab_T *find_var_ht __ARGS((char_u *name, char_u **varname));
@@ -1023,7 +1025,7 @@ eval_to_bool(arg, error, nextcmd, skip)
 	*error = FALSE;
 	if (!skip)
 	{
-	    retval = (get_tv_number(&tv) != 0);
+	    retval = (get_tv_number_chk(&tv, error) != 0);
 	    clear_tv(&tv);
 	}
     }
@@ -1137,7 +1139,7 @@ eval_to_number(expr)
 	retval = -1;
     else
     {
-	retval = get_tv_number(&rettv);
+	retval = get_tv_number_chk(&rettv, NULL);
 	clear_tv(&rettv);
     }
     --emsg_off;
@@ -1775,8 +1777,8 @@ ex_let_one(arg, tv, copy, endchars, op)
 	    {
 		c1 = name[len];
 		name[len] = NUL;
-		p = get_tv_string(tv);
-		if (op != NULL && *op == '.')
+		p = get_tv_string_chk(tv);
+		if (p != NULL && op != NULL && *op == '.')
 		{
 		    int	    mustfree = FALSE;
 		    char_u  *s = vim_getenv(name, &mustfree);
@@ -1789,15 +1791,18 @@ ex_let_one(arg, tv, copy, endchars, op)
 		    }
 		}
 		if (p != NULL)
+		{
 		    vim_setenv(name, p);
-		if (STRICMP(name, "HOME") == 0)
-		    init_homedir();
-		else if (didset_vim && STRICMP(name, "VIM") == 0)
-		    didset_vim = FALSE;
-		else if (didset_vimruntime && STRICMP(name, "VIMRUNTIME") == 0)
-		    didset_vimruntime = FALSE;
+		    if (STRICMP(name, "HOME") == 0)
+			init_homedir();
+		    else if (didset_vim && STRICMP(name, "VIM") == 0)
+			didset_vim = FALSE;
+		    else if (didset_vimruntime
+					&& STRICMP(name, "VIMRUNTIME") == 0)
+			didset_vimruntime = FALSE;
+		    arg_end = arg;
+		}
 		name[len] = c1;
-		arg_end = arg;
 		vim_free(tofree);
 	    }
 	}
@@ -1827,8 +1832,8 @@ ex_let_one(arg, tv, copy, endchars, op)
 	    *p = NUL;
 
 	    n = get_tv_number(tv);
-	    s = get_tv_string(tv);
-	    if (op != NULL && *op != '=')
+	    s = get_tv_string_chk(tv);	    /* != NULL if number or string */
+	    if (s != NULL && op != NULL && *op != '=')
 	    {
 		opt_type = get_option_value(arg, &numval,
 						       &stringval, opt_flags);
@@ -1852,9 +1857,12 @@ ex_let_one(arg, tv, copy, endchars, op)
 		    }
 		}
 	    }
-	    set_option_value(arg, n, s, opt_flags);
+	    if (s != NULL)
+	    {
+		set_option_value(arg, n, s, opt_flags);
+		arg_end = p;
+	    }
 	    *p = c1;
-	    arg_end = p;
 	    vim_free(stringval);
 	}
     }
@@ -1875,8 +1883,8 @@ ex_let_one(arg, tv, copy, endchars, op)
 	    char_u	*tofree = NULL;
 	    char_u	*s;
 
-	    p = get_tv_string(tv);
-	    if (op != NULL && *op == '.')
+	    p = get_tv_string_chk(tv);
+	    if (p != NULL && op != NULL && *op == '.')
 	    {
 		s = get_reg_contents(*arg == '@' ? '"' : *arg, FALSE, FALSE);
 		if (s != NULL)
@@ -1886,8 +1894,10 @@ ex_let_one(arg, tv, copy, endchars, op)
 		}
 	    }
 	    if (p != NULL)
+	    {
 		write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE);
-	    arg_end = arg + 1;
+		arg_end = arg + 1;
+	    }
 	    vim_free(tofree);
 	}
     }
@@ -2070,6 +2080,12 @@ get_lval(name, rettv, lp, unlet, skip, q
 		empty1 = FALSE;
 		if (eval1(&p, &var1, TRUE) == FAIL)	/* recursive! */
 		    return NULL;
+		if (get_tv_string_chk(&var1) == NULL)
+		{
+		    /* not a number or string */
+		    clear_tv(&var1);
+		    return NULL;
+		}
 	    }
 
 	    /* Optionally get the second index [ :expr]. */
@@ -2104,6 +2120,14 @@ get_lval(name, rettv, lp, unlet, skip, q
 			    clear_tv(&var1);
 			return NULL;
 		    }
+		    if (get_tv_string_chk(&var2) == NULL)
+		    {
+			/* not a number or string */
+			if (!empty1)
+			    clear_tv(&var1);
+			clear_tv(&var2);
+			return NULL;
+		    }
 		}
 		lp->ll_range = TRUE;
 	    }
@@ -2130,7 +2154,7 @@ get_lval(name, rettv, lp, unlet, skip, q
 	    if (len == -1)
 	    {
 		/* "[key]": get key from "var1" */
-		key = get_tv_string(&var1);
+		key = get_tv_string(&var1);	/* is number or string */
 		if (*key == NUL)
 		{
 		    if (!quiet)
@@ -2176,7 +2200,7 @@ get_lval(name, rettv, lp, unlet, skip, q
 		lp->ll_n1 = 0;
 	    else
 	    {
-		lp->ll_n1 = get_tv_number(&var1);
+		lp->ll_n1 = get_tv_number(&var1);   /* is number or string */
 		clear_tv(&var1);
 	    }
 	    lp->ll_dict = NULL;
@@ -2199,7 +2223,7 @@ get_lval(name, rettv, lp, unlet, skip, q
 	     */
 	    if (lp->ll_range && !lp->ll_empty2)
 	    {
-		lp->ll_n2 = get_tv_number(&var2);
+		lp->ll_n2 = get_tv_number(&var2);   /* is number or string */
 		clear_tv(&var2);
 		if (lp->ll_n2 < 0)
 		{
@@ -3340,9 +3364,13 @@ eval1(arg, rettv, evaluate)
 	result = FALSE;
 	if (evaluate)
 	{
-	    if (get_tv_number(rettv) != 0)
+	    int		error = FALSE;
+
+	    if (get_tv_number_chk(rettv, &error) != 0)
 		result = TRUE;
 	    clear_tv(rettv);
+	    if (error)
+		return FAIL;
 	}
 
 	/*
@@ -3398,6 +3426,7 @@ eval2(arg, rettv, evaluate)
     typval_T	var2;
     long	result;
     int		first;
+    int		error = FALSE;
 
     /*
      * Get the first variable.
@@ -3414,9 +3443,11 @@ eval2(arg, rettv, evaluate)
     {
 	if (evaluate && first)
 	{
-	    if (get_tv_number(rettv) != 0)
+	    if (get_tv_number_chk(rettv, &error) != 0)
 		result = TRUE;
 	    clear_tv(rettv);
+	    if (error)
+		return FAIL;
 	    first = FALSE;
 	}
 
@@ -3432,9 +3463,11 @@ eval2(arg, rettv, evaluate)
 	 */
 	if (evaluate && !result)
 	{
-	    if (get_tv_number(&var2) != 0)
+	    if (get_tv_number_chk(&var2, &error) != 0)
 		result = TRUE;
 	    clear_tv(&var2);
+	    if (error)
+		return FAIL;
 	}
 	if (evaluate)
 	{
@@ -3464,6 +3497,7 @@ eval3(arg, rettv, evaluate)
     typval_T	var2;
     long	result;
     int		first;
+    int		error = FALSE;
 
     /*
      * Get the first variable.
@@ -3480,9 +3514,11 @@ eval3(arg, rettv, evaluate)
     {
 	if (evaluate && first)
 	{
-	    if (get_tv_number(rettv) == 0)
+	    if (get_tv_number_chk(rettv, &error) == 0)
 		result = FALSE;
 	    clear_tv(rettv);
+	    if (error)
+		return FAIL;
 	    first = FALSE;
 	}
 
@@ -3498,9 +3534,11 @@ eval3(arg, rettv, evaluate)
 	 */
 	if (evaluate && result)
 	{
-	    if (get_tv_number(&var2) == 0)
+	    if (get_tv_number_chk(&var2, &error) == 0)
 		result = FALSE;
 	    clear_tv(&var2);
+	    if (error)
+		return FAIL;
 	}
 	if (evaluate)
 	{
@@ -3832,6 +3870,22 @@ eval5(arg, rettv, evaluate)
 	if (op != '+' && op != '-' && op != '.')
 	    break;
 
+	if (op != '+' || rettv->v_type != VAR_LIST)
+	{
+	    /* For "list + ...", an illegal use of the first operand as
+	     * a number cannot be determined before evaluating the 2nd
+	     * operand: if this is also a list, all is ok.
+	     * For "something . ...", "something - ..." or "non-list + ...",
+	     * we know that the first operand needs to be a string or number
+	     * without evaluating the 2nd operand.  So check before to avoid
+	     * side effects after an error. */
+	    if (evaluate && get_tv_string_chk(rettv) == NULL)
+	    {
+		clear_tv(rettv);
+		return FAIL;
+	    }
+	}
+
 	/*
 	 * Get the second variable.
 	 */
@@ -3849,8 +3903,14 @@ eval5(arg, rettv, evaluate)
 	     */
 	    if (op == '.')
 	    {
-		s1 = get_tv_string_buf(rettv, buf1);
-		s2 = get_tv_string_buf(&var2, buf2);
+		s1 = get_tv_string_buf(rettv, buf1);	/* already checked */
+		s2 = get_tv_string_buf_chk(&var2, buf2);
+		if (s2 == NULL)		/* type error ? */
+		{
+		    clear_tv(rettv);
+		    clear_tv(&var2);
+		    return FAIL;
+		}
 		p = concat_str(s1, s2);
 		clear_tv(rettv);
 		rettv->v_type = VAR_STRING;
@@ -3872,8 +3932,24 @@ eval5(arg, rettv, evaluate)
 	    }
 	    else
 	    {
-		n1 = get_tv_number(rettv);
-		n2 = get_tv_number(&var2);
+		int	    error = FALSE;
+
+		n1 = get_tv_number_chk(rettv, &error);
+		if (error)
+		{
+		    /* This can only happen for "list + non-list".
+		     * For "non-list + ..." or "something - ...", we returned
+		     * before evaluating the 2nd operand. */
+		    clear_tv(rettv);
+		    return FAIL;
+		}
+		n2 = get_tv_number_chk(&var2, &error);
+		if (error)
+		{
+		    clear_tv(rettv);
+		    clear_tv(&var2);
+		    return FAIL;
+		}
 		clear_tv(rettv);
 		if (op == '+')
 		    n1 = n1 + n2;
@@ -3908,6 +3984,7 @@ eval6(arg, rettv, evaluate)
     typval_T	var2;
     int		op;
     long	n1, n2;
+    int		error = FALSE;
 
     /*
      * Get the first variable.
@@ -3926,8 +4003,10 @@ eval6(arg, rettv, evaluate)
 
 	if (evaluate)
 	{
-	    n1 = get_tv_number(rettv);
+	    n1 = get_tv_number_chk(rettv, &error);
 	    clear_tv(rettv);
+	    if (error)
+		return FAIL;
 	}
 	else
 	    n1 = 0;
@@ -3941,8 +4020,10 @@ eval6(arg, rettv, evaluate)
 
 	if (evaluate)
 	{
-	    n2 = get_tv_number(&var2);
+	    n2 = get_tv_number_chk(&var2, &error);
 	    clear_tv(&var2);
+	    if (error)
+		return FAIL;
 
 	    /*
 	     * Compute the result.
@@ -4175,18 +4256,28 @@ eval7(arg, rettv, evaluate)
      */
     if (ret == OK && evaluate && end_leader > start_leader)
     {
-	val = get_tv_number(rettv);
-	while (end_leader > start_leader)
-	{
-	    --end_leader;
-	    if (*end_leader == '!')
-		val = !val;
-	    else if (*end_leader == '-')
-		val = -val;
-	}
-	clear_tv(rettv);
-	rettv->v_type = VAR_NUMBER;
-	rettv->vval.v_number = val;
+	int	    error = FALSE;
+
+	val = get_tv_number_chk(rettv, &error);
+	if (error)
+	{
+	    clear_tv(rettv);
+	    ret = FAIL;
+	}
+	else
+	{
+	    while (end_leader > start_leader)
+	    {
+		--end_leader;
+		if (*end_leader == '!')
+		    val = !val;
+		else if (*end_leader == '-')
+		    val = -val;
+	    }
+	    clear_tv(rettv);
+	    rettv->v_type = VAR_NUMBER;
+	    rettv->vval.v_number = val;
+	}
     }
 
     return ret;
@@ -4243,6 +4334,12 @@ eval_index(arg, rettv, evaluate, verbose
 	    empty1 = TRUE;
 	else if (eval1(arg, &var1, evaluate) == FAIL)	/* recursive! */
 	    return FAIL;
+	else if (evaluate && get_tv_string_chk(&var1) == NULL)
+	{
+	    /* not a number or string */
+	    clear_tv(&var1);
+	    return FAIL;
+	}
 
 	/*
 	 * Get the second variable from inside the [:].
@@ -4255,7 +4352,16 @@ eval_index(arg, rettv, evaluate, verbose
 		empty2 = TRUE;
 	    else if (eval1(arg, &var2, evaluate) == FAIL)	/* recursive! */
 	    {
-		clear_tv(&var1);
+		if (!empty1)
+		    clear_tv(&var1);
+		return FAIL;
+	    }
+	    else if (evaluate && get_tv_string_chk(&var2) == NULL)
+	    {
+		/* not a number or string */
+		if (!empty1)
+		    clear_tv(&var1);
+		clear_tv(&var2);
 		return FAIL;
 	    }
 	}
@@ -4928,6 +5034,7 @@ tv_equal(tv1, tv2, ic)
     int	    ic;	    /* ignore case */
 {
     char_u	buf1[NUMBUFLEN], buf2[NUMBUFLEN];
+    char_u	*s1, *s2;
 
     if (tv1->v_type == VAR_LIST || tv2->v_type == VAR_LIST)
     {
@@ -4963,12 +5070,13 @@ tv_equal(tv1, tv2, ic)
 	if (get_tv_number(tv1) != get_tv_number(tv2))
 	    return FALSE;
     }
-    else if (!ic && STRCMP(get_tv_string_buf(tv1, buf1),
-				       get_tv_string_buf(tv2, buf2)) != 0)
-	return FALSE;
-    else if (ic && STRICMP(get_tv_string_buf(tv1, buf1),
-				       get_tv_string_buf(tv2, buf2)) != 0)
-	return FALSE;
+    else
+    {
+	s1 = get_tv_string_buf(tv1, buf1);
+	s2 = get_tv_string_buf(tv2, buf2);
+	if ((ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2)) != 0)
+	    return FALSE;
+    }
     return TRUE;
 }
 
@@ -5828,10 +5936,12 @@ get_dict_tv(arg, rettv, evaluate)
 	    clear_tv(&tvkey);
 	    goto failret;
 	}
-	key = get_tv_string_buf(&tvkey, buf);
-	if (*key == NUL)
-	{
-	    EMSG(_(e_emptykey));
+	key = get_tv_string_buf_chk(&tvkey, buf);
+	if (key == NULL || *key == NUL)
+	{
+	    /* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */
+	    if (key != NULL)
+		EMSG(_(e_emptykey));
 	    clear_tv(&tvkey);
 	    goto failret;
 	}
@@ -6731,12 +6841,12 @@ f_append(argvars, rettv)
     typval_T	*rettv;
 {
     long	lnum;
+    char_u	*line;
     list_T	*l = NULL;
     listitem_T	*li = NULL;
     typval_T	*tv;
     long	added = 0;
 
-    rettv->vval.v_number = 1;		/* Default: Failed */
     lnum = get_tv_lnum(argvars);
     if (lnum >= 0
 	    && lnum <= curbuf->b_ml.ml_line_count
@@ -6749,6 +6859,7 @@ f_append(argvars, rettv)
 		return;
 	    li = l->lv_first;
 	}
+	rettv->vval.v_number = 0;	/* Default: Success */
 	for (;;)
 	{
 	    if (l == NULL)
@@ -6757,7 +6868,13 @@ f_append(argvars, rettv)
 		break;			/* end of list */
 	    else
 		tv = &li->li_tv;	/* append item from list */
-	    ml_append(lnum + added, get_tv_string(tv), (colnr_T)0, FALSE);
+	    line = get_tv_string_chk(tv);
+	    if (line == NULL)		/* type error */
+	    {
+		rettv->vval.v_number = 1;	/* Failed */
+		break;
+	    }
+	    ml_append(lnum + added, line, (colnr_T)0, FALSE);
 	    ++added;
 	    if (l == NULL)
 		break;
@@ -6767,8 +6884,9 @@ f_append(argvars, rettv)
 	appended_lines_mark(lnum, added);
 	if (curwin->w_cursor.lnum > lnum)
 	    curwin->w_cursor.lnum += added;
-	rettv->vval.v_number = 0;	/* Success */
-    }
+    }
+    else
+	rettv->vval.v_number = 1;	/* Failed */
 }
 
 /*
@@ -6805,7 +6923,7 @@ f_argv(argvars, rettv)
 {
     int		idx;
 
-    idx = get_tv_number(&argvars[0]);
+    idx = get_tv_number_chk(&argvars[0], NULL);
     if (idx >= 0 && idx < ARGCOUNT)
 	rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
     else
@@ -6829,13 +6947,17 @@ f_browse(argvars, rettv)
     char_u	*defname;
     char_u	buf[NUMBUFLEN];
     char_u	buf2[NUMBUFLEN];
-
-    save = get_tv_number(&argvars[0]);
-    title = get_tv_string(&argvars[1]);
-    initdir = get_tv_string_buf(&argvars[2], buf);
-    defname = get_tv_string_buf(&argvars[3], buf2);
-
-    rettv->vval.v_string =
+    int		error = FALSE;
+
+    save = get_tv_number_chk(&argvars[0], &error);
+    title = get_tv_string_chk(&argvars[1]);
+    initdir = get_tv_string_buf_chk(&argvars[2], buf);
+    defname = get_tv_string_buf_chk(&argvars[3], buf2);
+
+    if (error || title == NULL || initdir == NULL || defname == NULL)
+	rettv->vval.v_string = NULL;
+    else
+	rettv->vval.v_string =
 		 do_browse(save ? BROWSE_SAVE : 0,
 				 title, defname, NULL, initdir, NULL, curbuf);
 #else
@@ -6858,10 +6980,13 @@ f_browsedir(argvars, rettv)
     char_u	*initdir;
     char_u	buf[NUMBUFLEN];
 
-    title = get_tv_string(&argvars[0]);
-    initdir = get_tv_string_buf(&argvars[1], buf);
-
-    rettv->vval.v_string = do_browse(BROWSE_DIR,
+    title = get_tv_string_chk(&argvars[0]);
+    initdir = get_tv_string_buf_chk(&argvars[1], buf);
+
+    if (title == NULL || initdir == NULL)
+	rettv->vval.v_string = NULL;
+    else
+	rettv->vval.v_string = do_browse(BROWSE_DIR,
 				    title, NULL, NULL, initdir, NULL, curbuf);
 #else
     rettv->vval.v_string = NULL;
@@ -6994,6 +7119,7 @@ f_bufname(argvars, rettv)
 {
     buf_T	*buf;
 
+    (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
     ++emsg_off;
     buf = get_buf_tv(&argvars[0]);
     rettv->v_type = VAR_STRING;
@@ -7014,6 +7140,7 @@ f_bufnr(argvars, rettv)
 {
     buf_T	*buf;
 
+    (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
     ++emsg_off;
     buf = get_buf_tv(&argvars[0]);
     if (buf != NULL)
@@ -7037,6 +7164,7 @@ f_bufwinnr(argvars, rettv)
 #endif
     buf_T	*buf;
 
+    (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
     ++emsg_off;
     buf = get_buf_tv(&argvars[0]);
 #ifdef FEAT_WINDOWS
@@ -7067,7 +7195,7 @@ f_byte2line(argvars, rettv)
 #else
     long	boff = 0;
 
-    boff = get_tv_number(&argvars[0]) - 1;
+    boff = get_tv_number(&argvars[0]) - 1;  /* boff gets -1 on type error */
     if (boff < 0)
 	rettv->vval.v_number = -1;
     else
@@ -7091,10 +7219,10 @@ f_byteidx(argvars, rettv)
     char_u	*str;
     long	idx;
 
-    str = get_tv_string(&argvars[0]);
-    idx = get_tv_number(&argvars[1]);
+    str = get_tv_string_chk(&argvars[0]);
+    idx = get_tv_number_chk(&argvars[1], NULL);
     rettv->vval.v_number = -1;
-    if (idx < 0)
+    if (str == NULL || idx < 0)
 	return;
 
 #ifdef FEAT_MBYTE
@@ -7140,6 +7268,8 @@ f_call(argvars, rettv)
 	func = argvars[0].vval.v_string;
     else
 	func = get_tv_string(&argvars[0]);
+    if (*func == NUL)
+	return;		/* type error or empty name */
 
     if (argvars[2].v_type != VAR_UNKNOWN)
     {
@@ -7185,8 +7315,7 @@ f_char2nr(argvars, rettv)
 {
 #ifdef FEAT_MBYTE
     if (has_mbyte)
-	rettv->vval.v_number =
-				(*mb_ptr2char)(get_tv_string(&argvars[0]));
+	rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
     else
 #endif
     rettv->vval.v_number = get_tv_string(&argvars[0])[0];
@@ -7285,26 +7414,35 @@ f_confirm(argvars, rettv)
     char_u	buf2[NUMBUFLEN];
     int		def = 1;
     int		type = VIM_GENERIC;
-    int		c;
-
-    message = get_tv_string(&argvars[0]);
+    char_u	*typestr;
+    int		error = FALSE;
+
+    message = get_tv_string_chk(&argvars[0]);
+    if (message == NULL)
+	error = TRUE;
     if (argvars[1].v_type != VAR_UNKNOWN)
     {
-	buttons = get_tv_string_buf(&argvars[1], buf);
+	buttons = get_tv_string_buf_chk(&argvars[1], buf);
+	if (buttons == NULL)
+	    error = TRUE;
 	if (argvars[2].v_type != VAR_UNKNOWN)
 	{
-	    def = get_tv_number(&argvars[2]);
+	    def = get_tv_number_chk(&argvars[2], &error);
 	    if (argvars[3].v_type != VAR_UNKNOWN)
 	    {
-		/* avoid that TOUPPER_ASC calls get_tv_string_buf() twice */
-		c = *get_tv_string_buf(&argvars[3], buf2);
-		switch (TOUPPER_ASC(c))
-		{
-		    case 'E': type = VIM_ERROR; break;
-		    case 'Q': type = VIM_QUESTION; break;
-		    case 'I': type = VIM_INFO; break;
-		    case 'W': type = VIM_WARNING; break;
-		    case 'G': type = VIM_GENERIC; break;
+		typestr = get_tv_string_buf_chk(&argvars[3], buf2);
+		if (typestr == NULL)
+		    error = TRUE;
+		else
+		{
+		    switch (TOUPPER_ASC(*typestr))
+		    {
+			case 'E': type = VIM_ERROR; break;
+			case 'Q': type = VIM_QUESTION; break;
+			case 'I': type = VIM_INFO; break;
+			case 'W': type = VIM_WARNING; break;
+			case 'G': type = VIM_GENERIC; break;
+		    }
 		}
 	    }
 	}
@@ -7313,7 +7451,10 @@ f_confirm(argvars, rettv)
     if (buttons == NULL || *buttons == NUL)
 	buttons = (char_u *)_("&Ok");
 
-    rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
+    if (error)
+	rettv->vval.v_number = 0;
+    else
+	rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
 								   def, NULL);
 #else
     rettv->vval.v_number = 0;
@@ -7353,14 +7494,21 @@ f_count(argvars, rettv)
 	    li = l->lv_first;
 	    if (argvars[2].v_type != VAR_UNKNOWN)
 	    {
-		ic = get_tv_number(&argvars[2]);
+		int error = FALSE;
+
+		ic = get_tv_number_chk(&argvars[2], &error);
 		if (argvars[3].v_type != VAR_UNKNOWN)
 		{
-		    idx = get_tv_number(&argvars[3]);
-		    li = list_find(l, idx);
-		    if (li == NULL)
-			EMSGN(_(e_listidx), idx);
-		}
+		    idx = get_tv_number_chk(&argvars[3], &error);
+		    if (!error)
+		    {
+			li = list_find(l, idx);
+			if (li == NULL)
+			    EMSGN(_(e_listidx), idx);
+		    }
+		}
+		if (error)
+		    li = NULL;
 	    }
 
 	    for ( ; li != NULL; li = li->li_next)
@@ -7376,14 +7524,16 @@ f_count(argvars, rettv)
 
 	if ((d = argvars[0].vval.v_dict) != NULL)
 	{
+	    int error = FALSE;
+
 	    if (argvars[2].v_type != VAR_UNKNOWN)
 	    {
-		ic = get_tv_number(&argvars[2]);
+		ic = get_tv_number_chk(&argvars[2], &error);
 		if (argvars[3].v_type != VAR_UNKNOWN)
 		    EMSG(_(e_invarg));
 	    }
 
-	    todo = d->dv_hashtab.ht_used;
+	    todo = error ? 0 : d->dv_hashtab.ht_used;
 	    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
 	    {
 		if (!HASHITEM_EMPTY(hi))
@@ -7446,9 +7596,11 @@ f_cursor(argvars, rettv)
     long	line, col;
 
     line = get_tv_lnum(argvars);
+    col = get_tv_number_chk(&argvars[1], NULL);
+    if (line < 0 || col < 0)
+	return;		/* type error; errmsg already given */
     if (line > 0)
 	curwin->w_cursor.lnum = line;
-    col = get_tv_number(&argvars[1]);
     if (col > 0)
 	curwin->w_cursor.col = col - 1;
 #ifdef FEAT_VIRTUALEDIT
@@ -7478,7 +7630,7 @@ f_deepcopy(argvars, rettv)
     int		noref = 0;
 
     if (argvars[1].v_type != VAR_UNKNOWN)
-	noref = get_tv_number(&argvars[1]);
+	noref = get_tv_number_chk(&argvars[1], NULL);
     if (noref < 0 || noref > 1)
 	EMSG(_(e_invarg));
     else
@@ -7549,6 +7701,8 @@ f_diff_hlID(argvars, rettv)
     int			filler_lines;
     int			col;
 
+    if (lnum < 0)	/* ignore type error in {lnum} arg */
+	lnum = 0;
     if (lnum != prev_lnum
 	    || changedtick != curbuf->b_changedtick
 	    || fnum != curbuf->b_fnum)
@@ -7578,7 +7732,7 @@ f_diff_hlID(argvars, rettv)
 
     if (hlID == HLF_CHD || hlID == HLF_TXD)
     {
-	col = get_tv_number(&argvars[1]) - 1;
+	col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
 	if (col >= change_start && col <= change_end)
 	    hlID = HLF_TXD;			/* changed text */
 	else
@@ -7650,11 +7804,15 @@ f_eval(argvars, rettv)
 {
     char_u	*s;
 
-    s = get_tv_string(&argvars[0]);
-    s = skipwhite(s);
-
-    if (eval1(&s, rettv, TRUE) == FAIL)
+    s = get_tv_string_chk(&argvars[0]);
+    if (s != NULL)
+	s = skipwhite(s);
+
+    if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
+    {
+	rettv->v_type = VAR_NUMBER;
 	rettv->vval.v_number = 0;
+    }
     else if (*s != NUL)
 	EMSG(_(e_trailing));
 }
@@ -7772,6 +7930,7 @@ f_expand(argvars, rettv)
     char_u	*errormsg;
     int		flags = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
     expand_T	xpc;
+    int		error = FALSE;
 
     rettv->v_type = VAR_STRING;
     s = get_tv_string(&argvars[0]);
@@ -7785,12 +7944,18 @@ f_expand(argvars, rettv)
     {
 	/* When the optional second argument is non-zero, don't remove matches
 	 * for 'suffixes' and 'wildignore' */
-	if (argvars[1].v_type != VAR_UNKNOWN && get_tv_number(&argvars[1]))
+	if (argvars[1].v_type != VAR_UNKNOWN
+				    && get_tv_number_chk(&argvars[1], &error))
 	    flags |= WILD_KEEP_ALL;
-	ExpandInit(&xpc);
-	xpc.xp_context = EXPAND_FILES;
-	rettv->vval.v_string = ExpandOne(&xpc, s, NULL, flags, WILD_ALL);
-	ExpandCleanup(&xpc);
+	if (!error)
+	{
+	    ExpandInit(&xpc);
+	    xpc.xp_context = EXPAND_FILES;
+	    rettv->vval.v_string = ExpandOne(&xpc, s, NULL, flags, WILD_ALL);
+	    ExpandCleanup(&xpc);
+	}
+	else
+	    rettv->vval.v_string = NULL;
     }
 }
 
@@ -7809,6 +7974,7 @@ f_extend(argvars, rettv)
 	list_T		*l1, *l2;
 	listitem_T	*item;
 	long		before;
+	int		error = FALSE;
 
 	l1 = argvars[0].vval.v_list;
 	l2 = argvars[1].vval.v_list;
@@ -7817,7 +7983,10 @@ f_extend(argvars, rettv)
 	{
 	    if (argvars[2].v_type != VAR_UNKNOWN)
 	    {
-		before = get_tv_number(&argvars[2]);
+		before = get_tv_number_chk(&argvars[2], &error);
+		if (error)
+		    return;		/* type error; errmsg already given */
+
 		if (before == l1->lv_len)
 		    item = NULL;
 		else
@@ -7857,7 +8026,9 @@ f_extend(argvars, rettv)
 	    {
 		static char *(av[]) = {"keep", "force", "error"};
 
-		action = get_tv_string(&argvars[2]);
+		action = get_tv_string_chk(&argvars[2]);
+		if (action == NULL)
+		    return;		/* type error; errmsg already given */
 		for (i = 0; i < 3; ++i)
 		    if (STRCMP(action, av[i]) == 0)
 			break;
@@ -7963,22 +8134,30 @@ findfilendir(argvars, rettv, dir)
 
     if (argvars[1].v_type != VAR_UNKNOWN)
     {
-	p = get_tv_string_buf(&argvars[1], pathbuf);
-	if (*p != NUL)
-	    path = p;
-
-	if (argvars[2].v_type != VAR_UNKNOWN)
-	    count = get_tv_number(&argvars[2]);
-    }
-
-    do
-    {
-	vim_free(fresult);
-	fresult = find_file_in_path_option(first ? fname : NULL,
-					    first ? (int)STRLEN(fname) : 0,
-					    0, first, path, dir, NULL);
-	first = FALSE;
-    } while (--count > 0 && fresult != NULL);
+	p = get_tv_string_buf_chk(&argvars[1], pathbuf);
+	if (p == NULL)
+	    count = -1;	    /* error */
+	else
+	{
+	    if (*p != NUL)
+		path = p;
+
+	    if (argvars[2].v_type != VAR_UNKNOWN)
+		count = get_tv_number_chk(&argvars[2], NULL); /* -1: error */
+	}
+    }
+
+    if (*fname != NUL && count >= 0)
+    {
+	do
+	{
+	    vim_free(fresult);
+	    fresult = find_file_in_path_option(first ? fname : NULL,
+					       first ? (int)STRLEN(fname) : 0,
+					       0, first, path, dir, NULL);
+	    first = FALSE;
+	} while (--count > 0 && fresult != NULL);
+    }
 
     rettv->vval.v_string = fresult;
 #else
@@ -8073,52 +8252,59 @@ filter_map(argvars, rettv, map)
 	return;
     }
 
-    prepare_vimvar(VV_VAL, &save_val);
-    expr = skipwhite(get_tv_string_buf(&argvars[1], buf));
-
-    if (argvars[0].v_type == VAR_DICT)
-    {
-	prepare_vimvar(VV_KEY, &save_key);
-	vimvars[VV_KEY].vv_type = VAR_STRING;
-
-	ht = &d->dv_hashtab;
-	hash_lock(ht);
-	todo = ht->ht_used;
-	for (hi = ht->ht_array; todo > 0; ++hi)
-	{
-	    if (!HASHITEM_EMPTY(hi))
-	    {
-		--todo;
-		di = HI2DI(hi);
-		if (tv_check_lock(di->di_tv.v_lock, msg))
+    expr = get_tv_string_buf_chk(&argvars[1], buf);
+    /* On type errors, the preceding call has already displayed an error
+     * message.  Avoid a misleading error message for an empty string that
+     * was not passed as argument. */
+    if (expr != NULL)
+    {
+	prepare_vimvar(VV_VAL, &save_val);
+	expr = skipwhite(expr);
+
+	if (argvars[0].v_type == VAR_DICT)
+	{
+	    prepare_vimvar(VV_KEY, &save_key);
+	    vimvars[VV_KEY].vv_type = VAR_STRING;
+
+	    ht = &d->dv_hashtab;
+	    hash_lock(ht);
+	    todo = ht->ht_used;
+	    for (hi = ht->ht_array; todo > 0; ++hi)
+	    {
+		if (!HASHITEM_EMPTY(hi))
+		{
+		    --todo;
+		    di = HI2DI(hi);
+		    if (tv_check_lock(di->di_tv.v_lock, msg))
+			break;
+		    vimvars[VV_KEY].vv_str = vim_strsave(di->di_key);
+		    if (filter_map_one(&di->di_tv, expr, map, &rem) == FAIL)
+			break;
+		    if (!map && rem)
+			dictitem_remove(d, di);
+		    clear_tv(&vimvars[VV_KEY].vv_tv);
+		}
+	    }
+	    hash_unlock(ht);
+
+	    restore_vimvar(VV_KEY, &save_key);
+	}
+	else
+	{
+	    for (li = l->lv_first; li != NULL; li = nli)
+	    {
+		if (tv_check_lock(li->li_tv.v_lock, msg))
 		    break;
-		vimvars[VV_KEY].vv_str = vim_strsave(di->di_key);
-		if (filter_map_one(&di->di_tv, expr, map, &rem) == FAIL)
+		nli = li->li_next;
+		if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL)
 		    break;
 		if (!map && rem)
-		    dictitem_remove(d, di);
-		clear_tv(&vimvars[VV_KEY].vv_tv);
-	    }
-	}
-	hash_unlock(ht);
-
-	restore_vimvar(VV_KEY, &save_key);
-    }
-    else
-    {
-	for (li = l->lv_first; li != NULL; li = nli)
-	{
-	    if (tv_check_lock(li->li_tv.v_lock, msg))
-		break;
-	    nli = li->li_next;
-	    if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL)
-		break;
-	    if (!map && rem)
-		listitem_remove(l, li);
-	}
-    }
-
-    restore_vimvar(VV_VAL, &save_val);
+		    listitem_remove(l, li);
+	    }
+	}
+
+	restore_vimvar(VV_VAL, &save_val);
+    }
 
     copy_tv(&argvars[0], rettv);
 }
@@ -8150,9 +8336,15 @@ filter_map_one(tv, expr, map, remp)
     }
     else
     {
+	int	    error = FALSE;
+
 	/* filter(): when expr is zero remove the item */
-	*remp = (get_tv_number(&rettv) == 0);
+	*remp = (get_tv_number_chk(&rettv, &error) == 0);
 	clear_tv(&rettv);
+	/* On type error, nothing has been removed; return FAIL to stop the
+	 * loop.  The error message was given by get_tv_number_chk(). */
+	if (error)
+	    return FAIL;
     }
     clear_tv(&vimvars[VV_VAL].vv_tv);
     return OK;
@@ -8206,11 +8398,15 @@ f_fnamemodify(argvars, rettv)
     char_u	*fbuf = NULL;
     char_u	buf[NUMBUFLEN];
 
-    fname = get_tv_string(&argvars[0]);
-    mods = get_tv_string_buf(&argvars[1], buf);
-    len = (int)STRLEN(fname);
-
-    (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
+    fname = get_tv_string_chk(&argvars[0]);
+    mods = get_tv_string_buf_chk(&argvars[1], buf);
+    if (fname == NULL || mods == NULL)
+	fname = NULL;
+    else
+    {
+	len = (int)STRLEN(fname);
+	(void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
+    }
 
     rettv->v_type = VAR_STRING;
     if (fname == NULL)
@@ -8381,6 +8577,9 @@ f_foldtextresult(argvars, rettv)
     rettv->vval.v_string = NULL;
 #ifdef FEAT_FOLDING
     lnum = get_tv_lnum(argvars);
+    /* treat illegal types and illegal string values for {lnum} the same */
+    if (lnum < 0)
+	lnum = 0;
     fold_count = foldedCount(curwin, lnum, &foldinfo);
     if (fold_count > 0)
     {
@@ -8455,8 +8654,10 @@ f_get(argvars, rettv)
     {
 	if ((l = argvars[0].vval.v_list) != NULL)
 	{
-	    li = list_find(l, get_tv_number(&argvars[1]));
-	    if (li != NULL)
+	    int		error = FALSE;
+
+	    li = list_find(l, get_tv_number_chk(&argvars[1], &error));
+	    if (!error && li != NULL)
 		tv = &li->li_tv;
 	}
     }
@@ -8496,9 +8697,10 @@ f_getbufvar(argvars, rettv)
     char_u	*varname;
     dictitem_T	*v;
 
+    (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
+    varname = get_tv_string_chk(&argvars[1]);
     ++emsg_off;
     buf = get_buf_tv(&argvars[0]);
-    varname = get_tv_string(&argvars[1]);
 
     rettv->v_type = VAR_STRING;
     rettv->vval.v_string = NULL;
@@ -8518,6 +8720,11 @@ f_getbufvar(argvars, rettv)
 	}
 	else
 	{
+	    if (*varname == NUL)
+		/* let getbufvar({nr}, "") return the "b:" dictionary.  The
+		 * scope prefix before the NUL byte is required by
+		 * find_var_in_ht(). */
+		varname = (char_u *)"b:" + 2;
 	    /* look up the variable */
 	    v = find_var_in_ht(&buf->b_vars.dv_hashtab, varname, FALSE);
 	    if (v != NULL)
@@ -8537,17 +8744,18 @@ f_getchar(argvars, rettv)
     typval_T	*rettv;
 {
     varnumber_T		n;
+    int			error = FALSE;
 
     ++no_mapping;
     ++allow_keys;
     if (argvars[0].v_type == VAR_UNKNOWN)
 	/* getchar(): blocking wait. */
 	n = safe_vgetc();
-    else if (get_tv_number(&argvars[0]) == 1)
+    else if (get_tv_number_chk(&argvars[0], &error) == 1)
 	/* getchar(1): only check if char avail */
 	n = vpeekc();
-    else if (vpeekc() == NUL)
-	/* getchar(0) and no char avail: return zero */
+    else if (error || vpeekc() == NUL)
+	/* illegal argument or getchar(0) and no char avail: return zero */
 	n = 0;
     else
 	/* getchar(0) and char avail: return char */
@@ -8858,8 +9066,9 @@ f_getline(argvars, rettv)
     listitem_T	*li;
 
     lnum = get_tv_lnum(argvars);
-
-    if (argvars[1].v_type == VAR_UNKNOWN)
+    if (lnum < 0)
+	rettv->vval.v_number = 0;   /* failure; error message already given */
+    else if (argvars[1].v_type == VAR_UNKNOWN)
     {
 	if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
 	    p = ml_get(lnum);
@@ -8874,7 +9083,8 @@ f_getline(argvars, rettv)
 	end = get_tv_lnum(&argvars[1]);
 	if (end < lnum)
 	{
-	    EMSG(_(e_invrange));
+	    if (end >= 0)	    /* else: error message already given */
+		EMSG(_(e_invrange));
 	    rettv->vval.v_number = 0;
 	}
 	else
@@ -8945,12 +9155,14 @@ f_getreg(argvars, rettv)
     char_u	*strregname;
     int		regname;
     int		arg2 = FALSE;
+    int		error = FALSE;
 
     if (argvars[0].v_type != VAR_UNKNOWN)
     {
-	strregname = get_tv_string(&argvars[0]);
+	strregname = get_tv_string_chk(&argvars[0]);
+	error = strregname == NULL;
 	if (argvars[1].v_type != VAR_UNKNOWN)
-	    arg2 = get_tv_number(&argvars[1]);
+	    arg2 = get_tv_number_chk(&argvars[1], &error);
     }
     else
 	strregname = vimvars[VV_REG].vv_str;
@@ -8959,7 +9171,8 @@ f_getreg(argvars, rettv)
 	regname = '"';
 
     rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = get_reg_contents(regname, TRUE, arg2);
+    rettv->vval.v_string = error ? NULL :
+				    get_reg_contents(regname, TRUE, arg2);
 }
 
 /*
@@ -8976,7 +9189,15 @@ f_getregtype(argvars, rettv)
     long	reglen = 0;
 
     if (argvars[0].v_type != VAR_UNKNOWN)
-	strregname = get_tv_string(&argvars[0]);
+    {
+	strregname = get_tv_string_chk(&argvars[0]);
+	if (strregname == NULL)	    /* type error; errmsg already given */
+	{
+	    rettv->v_type = VAR_STRING;
+	    rettv->vval.v_string = NULL;
+	    return;
+	}
+    }
     else
 	/* Default to v:register */
 	strregname = vimvars[VV_REG].vv_str;
@@ -9056,9 +9277,9 @@ f_getwinvar(argvars, rettv)
     char_u	*varname;
     dictitem_T	*v;
 
+    win = find_win_by_nr(&argvars[0]);
+    varname = get_tv_string_chk(&argvars[1]);
     ++emsg_off;
-    win = find_win_by_nr(&argvars[0]);
-    varname = get_tv_string(&argvars[1]);
 
     rettv->v_type = VAR_STRING;
     rettv->vval.v_string = NULL;
@@ -9081,6 +9302,11 @@ f_getwinvar(argvars, rettv)
 	}
 	else
 	{
+	    if (*varname == NUL)
+		/* let getwinvar({nr}, "") return the "w:" dictionary.  The
+		 * scope prefix before the NUL byte is required by
+		 * find_var_in_ht(). */
+		varname = (char_u *)"w:" + 2;
 	    /* look up the variable */
 	    v = find_var_in_ht(&win->w_vars.dv_hashtab, varname, FALSE);
 	    if (v != NULL)
@@ -9118,10 +9344,13 @@ f_globpath(argvars, rettv)
     typval_T	*rettv;
 {
     char_u	buf1[NUMBUFLEN];
+    char_u	*file = get_tv_string_buf_chk(&argvars[1], buf1);
 
     rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = globpath(get_tv_string(&argvars[0]),
-				     get_tv_string_buf(&argvars[1], buf1));
+    if (file == NULL)
+	rettv->vval.v_string = NULL;
+    else
+	rettv->vval.v_string = globpath(get_tv_string(&argvars[0]), file);
 }
 
 /*
@@ -9697,7 +9926,8 @@ f_histadd(argvars, rettv)
     if (check_restricted() || check_secure())
 	return;
 #ifdef FEAT_CMDHIST
-    histype = get_histtype(get_tv_string(&argvars[0]));
+    str = get_tv_string_chk(&argvars[0]);	/* NULL on type error */
+    histype = str != NULL ? get_histtype(str) : -1;
     if (histype >= 0)
     {
 	str = get_tv_string_buf(&argvars[1], buf);
@@ -9723,17 +9953,21 @@ f_histdel(argvars, rettv)
 #ifdef FEAT_CMDHIST
     int		n;
     char_u	buf[NUMBUFLEN];
-
-    if (argvars[1].v_type == VAR_UNKNOWN)
+    char_u	*str;
+
+    str = get_tv_string_chk(&argvars[0]);	/* NULL on type error */
+    if (str == NULL)
+	n = 0;
+    else if (argvars[1].v_type == VAR_UNKNOWN)
 	/* only one argument: clear entire history */
-	n = clr_history(get_histtype(get_tv_string(&argvars[0])));
+	n = clr_history(get_histtype(str));
     else if (argvars[1].v_type == VAR_NUMBER)
 	/* index given: remove that entry */
-	n = del_history_idx(get_histtype(get_tv_string(&argvars[0])),
+	n = del_history_idx(get_histtype(str),
 					  (int)get_tv_number(&argvars[1]));
     else
 	/* string given: remove all matching entries */
-	n = del_history_entry(get_histtype(get_tv_string(&argvars[0])),
+	n = del_history_entry(get_histtype(str),
 				      get_tv_string_buf(&argvars[1], buf));
     rettv->vval.v_number = n;
 #else
@@ -9753,13 +9987,21 @@ f_histget(argvars, rettv)
 #ifdef FEAT_CMDHIST
     int		type;
     int		idx;
-
-    type = get_histtype(get_tv_string(&argvars[0]));
-    if (argvars[1].v_type == VAR_UNKNOWN)
-	idx = get_history_idx(type);
-    else
-	idx = (int)get_tv_number(&argvars[1]);
-    rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
+    char_u	*str;
+
+    str = get_tv_string_chk(&argvars[0]);	/* NULL on type error */
+    if (str == NULL)
+	rettv->vval.v_string = NULL;
+    else
+    {
+	type = get_histtype(str);
+	if (argvars[1].v_type == VAR_UNKNOWN)
+	    idx = get_history_idx(type);
+	else
+	    idx = (int)get_tv_number_chk(&argvars[1], NULL);
+						    /* -1 on type error */
+	rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
+    }
 #else
     rettv->vval.v_string = NULL;
 #endif
@@ -9778,7 +10020,9 @@ f_histnr(argvars, rettv)
     int		i;
 
 #ifdef FEAT_CMDHIST
-    i = get_histtype(get_tv_string(&argvars[0]));
+    char_u	*history = get_tv_string_chk(&argvars[0]);
+
+    i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
     if (i >= HIST_CMD && i < HIST_COUNT)
 	i = get_history_idx(i);
     else
@@ -9905,12 +10149,16 @@ f_index(argvars, rettv)
 	item = l->lv_first;
 	if (argvars[2].v_type != VAR_UNKNOWN)
 	{
+	    int		error = FALSE;
+
 	    /* Start at specified item.  Use the cached index that list_find()
 	     * sets, so that a negative number also works. */
-	    item = list_find(l, get_tv_number(&argvars[2]));
+	    item = list_find(l, get_tv_number_chk(&argvars[2], &error));
 	    idx = l->lv_idx;
 	    if (argvars[3].v_type != VAR_UNKNOWN)
-		ic = get_tv_number(&argvars[3]);
+		ic = get_tv_number_chk(&argvars[3], &error);
+	    if (error)
+		item = NULL;
 	}
 
 	for ( ; item != NULL; item = item->li_next, ++idx)
@@ -9933,11 +10181,12 @@ f_input(argvars, rettv)
     typval_T	*argvars;
     typval_T	*rettv;
 {
-    char_u	*prompt = get_tv_string(&argvars[0]);
+    char_u	*prompt = get_tv_string_chk(&argvars[0]);
     char_u	*p = NULL;
     int		c;
     char_u	buf[NUMBUFLEN];
     int		cmd_silent_save = cmd_silent;
+    char_u	*defstr = (char_u *)"";
 
     rettv->v_type = VAR_STRING;
 
@@ -9971,17 +10220,22 @@ f_input(argvars, rettv)
 	    *p = c;
 	}
 	cmdline_row = msg_row;
-    }
-
-    if (argvars[1].v_type != VAR_UNKNOWN)
-	stuffReadbuffSpec(get_tv_string_buf(&argvars[1], buf));
-
-    rettv->vval.v_string =
+
+	if (argvars[1].v_type != VAR_UNKNOWN)
+	{
+	    defstr = get_tv_string_buf_chk(&argvars[1], buf);
+	    if (defstr != NULL)
+		stuffReadbuffSpec(defstr);
+	}
+
+	if (defstr != NULL)
+	    rettv->vval.v_string =
 		getcmdline_prompt(inputsecret_flag ? NUL : '@', p, echo_attr);
 
-    /* since the user typed this, no need to wait for return */
-    need_wait_return = FALSE;
-    msg_didout = FALSE;
+	/* since the user typed this, no need to wait for return */
+	need_wait_return = FALSE;
+	msg_didout = FALSE;
+    }
     cmd_silent = cmd_silent_save;
 }
 
@@ -9999,21 +10253,25 @@ f_inputdialog(argvars, rettv)
     {
 	char_u	*message;
 	char_u	buf[NUMBUFLEN];
-
-	message = get_tv_string(&argvars[0]);
-	if (argvars[1].v_type != VAR_UNKNOWN)
-	{
-	    STRNCPY(IObuff, get_tv_string_buf(&argvars[1], buf), IOSIZE);
+	char_u	*defstr = (char_u *)"";
+
+	message = get_tv_string_chk(&argvars[0]);
+	if (argvars[1].v_type != VAR_UNKNOWN
+	    && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
+	{
+	    STRNCPY(IObuff, defstr, IOSIZE);
 	    IObuff[IOSIZE - 1] = NUL;
 	}
 	else
 	    IObuff[0] = NUL;
-	if (do_dialog(VIM_QUESTION, NULL, message, (char_u *)_("&OK\n&Cancel"),
-							      1, IObuff) == 1)
+	if (message != NULL && defstr != NULL
+		&& do_dialog(VIM_QUESTION, NULL, message,
+				(char_u *)_("&OK\n&Cancel"), 1, IObuff) == 1)
 	    rettv->vval.v_string = vim_strsave(IObuff);
 	else
 	{
-	    if (argvars[1].v_type != VAR_UNKNOWN
+	    if (message != NULL && defstr != NULL
+					&& argvars[1].v_type != VAR_UNKNOWN
 					&& argvars[2].v_type != VAR_UNKNOWN)
 		rettv->vval.v_string = vim_strsave(
 				      get_tv_string_buf(&argvars[2], buf));
@@ -10099,6 +10357,7 @@ f_insert(argvars, rettv)
     long	before = 0;
     listitem_T	*item;
     list_T	*l;
+    int		error = FALSE;
 
     rettv->vval.v_number = 0;
     if (argvars[0].v_type != VAR_LIST)
@@ -10107,7 +10366,9 @@ f_insert(argvars, rettv)
 	    && !tv_check_lock(l->lv_lock, (char_u *)"insert()"))
     {
 	if (argvars[2].v_type != VAR_UNKNOWN)
-	    before = get_tv_number(&argvars[2]);
+	    before = get_tv_number_chk(&argvars[2], &error);
+	if (error)
+	    return;		/* type error; errmsg already given */
 
 	if (before == l->lv_len)
 	    item = NULL;
@@ -10339,14 +10600,19 @@ f_join(argvars, rettv)
     if (argvars[1].v_type == VAR_UNKNOWN)
 	sep = (char_u *)" ";
     else
-	sep = get_tv_string(&argvars[1]);
-
-    ga_init2(&ga, (int)sizeof(char), 80);
-    list_join(&ga, argvars[0].vval.v_list, sep, TRUE);
-    ga_append(&ga, NUL);
+	sep = get_tv_string_chk(&argvars[1]);
 
     rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = (char_u *)ga.ga_data;
+
+    if (sep != NULL)
+    {
+	ga_init2(&ga, (int)sizeof(char), 80);
+	list_join(&ga, argvars[0].vval.v_list, sep, TRUE);
+	ga_append(&ga, NUL);
+	rettv->vval.v_string = (char_u *)ga.ga_data;
+    }
+    else
+	rettv->vval.v_string = NULL;
 }
 
 /*
@@ -10577,9 +10843,12 @@ get_maparg(argvars, rettv, exact)
 	return;
 
     if (argvars[1].v_type != VAR_UNKNOWN)
-	which = get_tv_string_buf(&argvars[1], buf);
+	which = get_tv_string_buf_chk(&argvars[1], buf);
     else
 	which = (char_u *)"";
+    if (which == NULL)
+	return;
+
     mode = get_map_mode(&which, 0);
 
     keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE);
@@ -10683,11 +10952,17 @@ find_some_match(argvars, rettv, type)
     else
 	expr = str = get_tv_string(&argvars[0]);
 
-    pat = get_tv_string_buf(&argvars[1], patbuf);
+    pat = get_tv_string_buf_chk(&argvars[1], patbuf);
+    if (pat == NULL)
+	goto theend;
 
     if (argvars[2].v_type != VAR_UNKNOWN)
     {
-	start = get_tv_number(&argvars[2]);
+	int	    error = FALSE;
+
+	start = get_tv_number_chk(&argvars[2], &error);
+	if (error)
+	    goto theend;
 	if (l != NULL)
 	{
 	    li = list_find(l, start);
@@ -10705,7 +10980,9 @@ find_some_match(argvars, rettv, type)
 	}
 
 	if (argvars[3].v_type != VAR_UNKNOWN)
-	    nth = get_tv_number(&argvars[3]);
+	    nth = get_tv_number_chk(&argvars[3], &error);
+	if (error)
+	    goto theend;
     }
 
     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
@@ -10856,6 +11133,7 @@ max_min(argvars, rettv, domax)
 {
     long	n = 0;
     long	i;
+    int		error = FALSE;
 
     if (argvars[0].v_type == VAR_LIST)
     {
@@ -10868,13 +11146,13 @@ max_min(argvars, rettv, domax)
 	    li = l->lv_first;
 	    if (li != NULL)
 	    {
-		n = get_tv_number(&li->li_tv);
+		n = get_tv_number_chk(&li->li_tv, &error);
 		while (1)
 		{
 		    li = li->li_next;
 		    if (li == NULL)
 			break;
-		    i = get_tv_number(&li->li_tv);
+		    i = get_tv_number_chk(&li->li_tv, &error);
 		    if (domax ? i > n : i < n)
 			n = i;
 		}
@@ -10897,7 +11175,7 @@ max_min(argvars, rettv, domax)
 		if (!HASHITEM_EMPTY(hi))
 		{
 		    --todo;
-		    i = get_tv_number(&HI2DI(hi)->di_tv);
+		    i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
 		    if (first)
 		    {
 			n = i;
@@ -10911,7 +11189,7 @@ max_min(argvars, rettv, domax)
     }
     else
 	EMSG(_(e_listdictarg));
-    rettv->vval.v_number = n;
+    rettv->vval.v_number = error ? 0 : n;
 }
 
 /*
@@ -10990,11 +11268,11 @@ f_mkdir(argvars, rettv)
     if (argvars[1].v_type != VAR_UNKNOWN)
     {
 	if (argvars[2].v_type != VAR_UNKNOWN)
-	    prot = get_tv_number(&argvars[2]);
-	if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
+	    prot = get_tv_number_chk(&argvars[2], NULL);
+	if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
 	    mkdir_recurse(dir, prot);
     }
-    rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
+    rettv->vval.v_number = prot != -1 ? vim_mkdir_emsg(dir, prot) : 0;
 }
 #endif
 
@@ -11050,7 +11328,7 @@ f_nextnonblank(argvars, rettv)
 
     for (lnum = get_tv_lnum(argvars); ; ++lnum)
     {
-	if (lnum > curbuf->b_ml.ml_line_count)
+	if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
 	{
 	    lnum = 0;
 	    break;
@@ -11117,8 +11395,9 @@ f_range(argvars, rettv)
     long	i;
     list_T	*l;
     listitem_T	*li;
-
-    start = get_tv_number(&argvars[0]);
+    int		error = FALSE;
+
+    start = get_tv_number_chk(&argvars[0], &error);
     if (argvars[1].v_type == VAR_UNKNOWN)
     {
 	end = start - 1;
@@ -11126,12 +11405,14 @@ f_range(argvars, rettv)
     }
     else
     {
-	end = get_tv_number(&argvars[1]);
+	end = get_tv_number_chk(&argvars[1], &error);
 	if (argvars[2].v_type != VAR_UNKNOWN)
-	    stride = get_tv_number(&argvars[2]);
+	    stride = get_tv_number_chk(&argvars[2], &error);
     }
 
     rettv->vval.v_number = 0;
+    if (error)
+	return;		/* type error; errmsg already given */
     if (stride == 0)
 	EMSG(_("E726: Stride is zero"));
     else if (stride > 0 ? end < start : end > start)
@@ -11375,7 +11656,9 @@ remote_common(argvars, rettv, expr)
 	return;
 # endif
 
-    server_name = get_tv_string(&argvars[0]);
+    server_name = get_tv_string_chk(&argvars[0]);
+    if (server_name == NULL)
+	return;		/* type error; errmsg already given */
     keys = get_tv_string_buf(&argvars[1], buf);
 # ifdef WIN32
     if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0)
@@ -11397,11 +11680,14 @@ remote_common(argvars, rettv, expr)
     {
 	dictitem_T	v;
 	char_u		str[30];
+	char_u		*idvar;
 
 	sprintf((char *)str, "0x%x", (unsigned int)w);
 	v.di_tv.v_type = VAR_STRING;
 	v.di_tv.vval.v_string = vim_strsave(str);
-	set_var(get_tv_string(&argvars[2]), &v.di_tv, FALSE);
+	idvar = get_tv_string_chk(&argvars[2]);
+	if (idvar != NULL)
+	    set_var(idvar, &v.di_tv, FALSE);
 	vim_free(v.di_tv.vval.v_string);
     }
 }
@@ -11436,7 +11722,12 @@ f_remote_foreground(argvars, rettv)
 #ifdef FEAT_CLIENTSERVER
 # ifdef WIN32
     /* On Win32 it's done in this application. */
-    serverForeground(get_tv_string(&argvars[0]));
+    {
+	char_u	*server_name = get_tv_string_chk(&argvars[0]);
+
+	if (server_name != NULL)
+	    serverForeground(server_name);
+    }
 # else
     /* Send a foreground() expression to the server. */
     argvars[1].v_type = VAR_STRING;
@@ -11460,14 +11751,21 @@ f_remote_peek(argvars, rettv)
 # ifdef WIN32
     int		n = 0;
 # endif
+    char_u	*serverid;
 
     if (check_restricted() || check_secure())
     {
 	rettv->vval.v_number = -1;
 	return;
     }
+    serverid = get_tv_string_chk(&argvars[0]);
+    if (serverid == NULL)
+    {
+	rettv->vval.v_number = -1;
+	return;		/* type error; errmsg already given */
+    }
 # ifdef WIN32
-    sscanf(get_tv_string(&argvars[0]), "%x", &n);
+    sscanf(serverid, "%x", &n);
     if (n == 0)
 	rettv->vval.v_number = -1;
     else
@@ -11481,14 +11779,18 @@ f_remote_peek(argvars, rettv)
 	return;
 
     rettv->vval.v_number = serverPeekReply(X_DISPLAY,
-			   serverStrToWin(get_tv_string(&argvars[0])), &s);
+						serverStrToWin(serverid), &s);
 # endif
 
     if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
     {
+	char_u		*retvar;
+
 	v.di_tv.v_type = VAR_STRING;
 	v.di_tv.vval.v_string = vim_strsave(s);
-	set_var(get_tv_string(&argvars[1]), &v.di_tv, FALSE);
+	retvar = get_tv_string_chk(&argvars[1]);
+	if (retvar != NULL)
+	    set_var(retvar, &v.di_tv, FALSE);
 	vim_free(v.di_tv.vval.v_string);
     }
 #else
@@ -11505,19 +11807,21 @@ f_remote_read(argvars, rettv)
     char_u	*r = NULL;
 
 #ifdef FEAT_CLIENTSERVER
-    if (!check_restricted() && !check_secure())
+    char_u	*serverid = get_tv_string_chk(&argvars[0]);
+
+    if (serverid != NULL && !check_restricted() && !check_secure())
     {
 # ifdef WIN32
 	/* The server's HWND is encoded in the 'id' parameter */
 	int		n = 0;
 
-	sscanf(get_tv_string(&argvars[0]), "%x", &n);
+	sscanf(serverid, "%x", &n);
 	if (n != 0)
 	    r = serverGetReply((HWND)n, FALSE, TRUE, TRUE);
 	if (r == NULL)
 # else
 	if (check_connection() == FAIL || serverReadReply(X_DISPLAY,
-		serverStrToWin(get_tv_string(&argvars[0])), &r, FALSE) < 0)
+		serverStrToWin(serverid), &r, FALSE) < 0)
 # endif
 	    EMSG(_("E277: Unable to read a server reply"));
     }
@@ -11567,15 +11871,18 @@ f_remove(argvars, rettv)
 	else if ((d = argvars[0].vval.v_dict) != NULL
 		&& !tv_check_lock(d->dv_lock, (char_u *)"remove()"))
 	{
-	    key = get_tv_string(&argvars[1]);
-	    di = dict_find(d, key, -1);
-	    if (di == NULL)
-		EMSG2(_(e_dictkey), key);
-	    else
-	    {
-		*rettv = di->di_tv;
-		init_tv(&di->di_tv);
-		dictitem_remove(d, di);
+	    key = get_tv_string_chk(&argvars[1]);
+	    if (key != NULL)
+	    {
+		di = dict_find(d, key, -1);
+		if (di == NULL)
+		    EMSG2(_(e_dictkey), key);
+		else
+		{
+		    *rettv = di->di_tv;
+		    init_tv(&di->di_tv);
+		    dictitem_remove(d, di);
+		}
 	    }
 	}
     }
@@ -11584,9 +11891,12 @@ f_remove(argvars, rettv)
     else if ((l = argvars[0].vval.v_list) != NULL
 	    && !tv_check_lock(l->lv_lock, (char_u *)"remove()"))
     {
-	idx = get_tv_number(&argvars[1]);
-	item = list_find(l, idx);
-	if (item == NULL)
+	int	    error = FALSE;
+
+	idx = get_tv_number_chk(&argvars[1], &error);
+	if (error)
+	    ;		/* type error: do nothing, errmsg already given */
+	else if ((item = list_find(l, idx)) == NULL)
 	    EMSGN(_(e_listidx), idx);
 	else
 	{
@@ -11600,9 +11910,10 @@ f_remove(argvars, rettv)
 	    else
 	    {
 		/* Remove range of items, return list with values. */
-		end = get_tv_number(&argvars[2]);
-		item2 = list_find(l, end);
-		if (item2 == NULL)
+		end = get_tv_number_chk(&argvars[2], &error);
+		if (error)
+		    ;		/* type error: do nothing */
+		else if ((item2 = list_find(l, end)) == NULL)
 		    EMSGN(_(e_listidx), end);
 		else
 		{
@@ -11964,7 +12275,9 @@ get_search_arg(varp, flagsp)
 
     if (varp->v_type != VAR_UNKNOWN)
     {
-	flags = get_tv_string_buf(varp, nbuf);
+	flags = get_tv_string_buf_chk(varp, nbuf);
+	if (flags == NULL)
+	    return 0;		/* type error; errmsg already given */
 	while (*flags != NUL)
 	{
 	    switch (*flags)
@@ -12051,7 +12364,7 @@ f_searchpair(argvars, rettv)
 {
     char_u	*spat, *mpat, *epat;
     char_u	*skip;
-    char_u	*pat, *pat2, *pat3;
+    char_u	*pat, *pat2 = NULL, *pat3 = NULL;
     pos_T	pos;
     pos_T	firstpos;
     pos_T	foundpos;
@@ -12076,9 +12389,11 @@ f_searchpair(argvars, rettv)
     p_cpo = (char_u *)"";
 
     /* Get the three pattern arguments: start, middle, end. */
-    spat = get_tv_string(&argvars[0]);
-    mpat = get_tv_string_buf(&argvars[1], nbuf1);
-    epat = get_tv_string_buf(&argvars[2], nbuf2);
+    spat = get_tv_string_chk(&argvars[0]);
+    mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
+    epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
+    if (spat == NULL || mpat == NULL || epat == NULL)
+	goto theend;	    /* type error */
 
     /* Make two search patterns: start/end (pat2, for in nested pairs) and
      * start/middle/end (pat3, for the top pair). */
@@ -12103,7 +12418,9 @@ f_searchpair(argvars, rettv)
 	    || argvars[4].v_type == VAR_UNKNOWN)
 	skip = (char_u *)"";
     else
-	skip = get_tv_string_buf(&argvars[4], nbuf3);
+	skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
+    if (skip == NULL)
+	goto theend;	    /* type error */
 
     save_cursor = curwin->w_cursor;
     pos = curwin->w_cursor;
@@ -12198,10 +12515,12 @@ f_server2client(argvars, rettv)
 {
 #ifdef FEAT_CLIENTSERVER
     char_u	buf[NUMBUFLEN];
-    char_u	*server = get_tv_string(&argvars[0]);
-    char_u	*reply = get_tv_string_buf(&argvars[1], buf);
+    char_u	*server = get_tv_string_chk(&argvars[0]);
+    char_u	*reply = get_tv_string_buf_chk(&argvars[1], buf);
 
     rettv->vval.v_number = -1;
+    if (server == NULL || reply == NULL)
+	return;
     if (check_restricted() || check_secure())
 	return;
 # ifdef FEAT_X11
@@ -12260,11 +12579,14 @@ f_setbufvar(argvars, rettv)
     typval_T	*varp;
     char_u	nbuf[NUMBUFLEN];
 
+    rettv->vval.v_number = 0;
+
     if (check_restricted() || check_secure())
 	return;
+    (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
+    varname = get_tv_string_chk(&argvars[1]);
     ++emsg_off;
     buf = get_buf_tv(&argvars[0]);
-    varname = get_tv_string(&argvars[1]);
     varp = &argvars[2];
 
     if (buf != NULL && varname != NULL && varp != NULL)
@@ -12279,9 +12601,17 @@ f_setbufvar(argvars, rettv)
 
 	if (*varname == '&')
 	{
+	    long	numval;
+	    char_u	*strval;
+	    int		error = FALSE;
+
 	    ++varname;
-	    set_option_value(varname, get_tv_number(varp),
-				 get_tv_string_buf(varp, nbuf), OPT_LOCAL);
+	    --emsg_off;
+	    numval = get_tv_number_chk(varp, &error);
+	    strval = get_tv_string_buf_chk(varp, nbuf);
+	    ++emsg_off;
+	    if (!error && strval != NULL)
+		set_option_value(varname, numval, strval, OPT_LOCAL);
 	}
 	else
 	{
@@ -12313,8 +12643,10 @@ f_setcmdpos(argvars, rettv)
     typval_T	*argvars;
     typval_T	*rettv;
 {
-    rettv->vval.v_number = set_cmdline_pos(
-				      (int)get_tv_number(&argvars[0]) - 1);
+    int		pos = (int)get_tv_number(&argvars[0]) - 1;
+
+    if (pos >= 0)
+	rettv->vval.v_number = set_cmdline_pos(pos);
 }
 
 /*
@@ -12339,7 +12671,7 @@ f_setline(argvars, rettv)
 	li = l->lv_first;
     }
     else
-	line = get_tv_string(&argvars[1]);
+	line = get_tv_string_chk(&argvars[1]);
 
     rettv->vval.v_number = 0;		/* OK */
     for (;;)
@@ -12349,12 +12681,12 @@ f_setline(argvars, rettv)
 	    /* list argument, get next string */
 	    if (li == NULL)
 		break;
-	    line = get_tv_string(&li->li_tv);
+	    line = get_tv_string_chk(&li->li_tv);
 	    li = li->li_next;
 	}
 
 	rettv->vval.v_number = 1;	/* FAIL */
-	if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
+	if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
 	    break;
 	if (lnum <= curbuf->b_ml.ml_line_count)
 	{
@@ -12406,7 +12738,9 @@ f_setqflist(argvars, rettv)
 
 	if (argvars[1].v_type == VAR_STRING)
 	{
-	    act = get_tv_string(&argvars[1]);
+	    act = get_tv_string_chk(&argvars[1]);
+	    if (act == NULL)
+		return;		/* type error; errmsg already given */
 	    if (*act == 'a' || *act == 'r')
 		action = *act;
 	}
@@ -12428,6 +12762,7 @@ f_setreg(argvars, rettv)
     int		regname;
     char_u	*strregname;
     char_u	*stropt;
+    char_u	*strval;
     int		append;
     char_u	yank_type;
     long	block_len;
@@ -12436,10 +12771,12 @@ f_setreg(argvars, rettv)
     yank_type = MAUTO;
     append = FALSE;
 
-    strregname = get_tv_string(argvars);
+    strregname = get_tv_string_chk(argvars);
     rettv->vval.v_number = 1;		/* FAIL is default */
 
-    regname = (strregname == NULL ? '"' : *strregname);
+    if (strregname == NULL)
+	return;		/* type error; errmsg already given */
+    regname = *strregname;
     if (regname == 0 || regname == '@')
 	regname = '"';
     else if (regname == '=')
@@ -12447,7 +12784,10 @@ f_setreg(argvars, rettv)
 
     if (argvars[2].v_type != VAR_UNKNOWN)
     {
-	for (stropt = get_tv_string(&argvars[2]); *stropt != NUL; ++stropt)
+	stropt = get_tv_string_chk(&argvars[2]);
+	if (stropt == NULL)
+	    return;		/* type error */
+	for (; *stropt != NUL; ++stropt)
 	    switch (*stropt)
 	    {
 		case 'a': case 'A':	/* append */
@@ -12473,7 +12813,9 @@ f_setreg(argvars, rettv)
 	    }
     }
 
-    write_reg_contents_ex(regname, get_tv_string(&argvars[1]), -1,
+    strval = get_tv_string_chk(&argvars[1]);
+    if (strval != NULL)
+	write_reg_contents_ex(regname, strval, -1,
 						append, yank_type, block_len);
     rettv->vval.v_number = 0;
 }
@@ -12496,11 +12838,13 @@ f_setwinvar(argvars, rettv)
     typval_T	*varp;
     char_u	nbuf[NUMBUFLEN];
 
+    rettv->vval.v_number = 0;
+
     if (check_restricted() || check_secure())
 	return;
+    win = find_win_by_nr(&argvars[0]);
+    varname = get_tv_string_chk(&argvars[1]);
     ++emsg_off;
-    win = find_win_by_nr(&argvars[0]);
-    varname = get_tv_string(&argvars[1]);
     varp = &argvars[2];
 
     if (win != NULL && varname != NULL && varp != NULL)
@@ -12514,9 +12858,17 @@ f_setwinvar(argvars, rettv)
 
 	if (*varname == '&')
 	{
+	    long	numval;
+	    char_u	*strval;
+	    int		error = FALSE;
+
 	    ++varname;
-	    set_option_value(varname, get_tv_number(varp),
-				 get_tv_string_buf(varp, nbuf), OPT_LOCAL);
+	    --emsg_off;
+	    numval = get_tv_number_chk(varp, &error);
+	    strval = get_tv_string_buf_chk(varp, nbuf);
+	    ++emsg_off;
+	    if (!error && strval != NULL)
+		set_option_value(varname, numval, strval, OPT_LOCAL);
 	}
 	else
 	{
@@ -12572,6 +12924,7 @@ static int
 
 static int	item_compare_ic;
 static char_u	*item_compare_func;
+static int	item_compare_func_err;
 #define ITEM_COMPARE_FAIL 999
 
 /*
@@ -12615,6 +12968,10 @@ item_compare2(s1, s2)
     typval_T	argv[2];
     int		dummy;
 
+    /* shortcut after failure in previous call; compare all items equal */
+    if (item_compare_func_err)
+	return 0;
+
     /* copy the values.  This is needed to be able to set v_lock to VAR_FIXED
      * in the copy without changing the original list items. */
     copy_tv(&(*(listitem_T **)s1)->li_tv, &argv[0]);
@@ -12629,7 +12986,10 @@ item_compare2(s1, s2)
     if (res == FAIL)
 	res = ITEM_COMPARE_FAIL;
     else
-	res = get_tv_number(&rettv);
+	/* return value has wrong type */
+	res = get_tv_number_chk(&rettv, &item_compare_func_err);
+    if (item_compare_func_err)
+	res = ITEM_COMPARE_FAIL;
     clear_tv(&rettv);
     return res;
 }
@@ -12669,10 +13029,14 @@ f_sort(argvars, rettv)
 	if (argvars[1].v_type != VAR_UNKNOWN)
 	{
 	    if (argvars[1].v_type == VAR_FUNC)
-		item_compare_func = argvars[0].vval.v_string;
-	    else
-	    {
-		i = get_tv_number(&argvars[1]);
+		item_compare_func = argvars[1].vval.v_string;
+	    else
+	    {
+		int	    error = FALSE;
+
+		i = get_tv_number_chk(&argvars[1], &error);
+		if (error)
+		    return;		/* type error; errmsg already given */
 		if (i == 1)
 		    item_compare_ic = TRUE;
 		else
@@ -12688,6 +13052,7 @@ f_sort(argvars, rettv)
 	for (li = l->lv_first; li != NULL; li = li->li_next)
 	    ptrs[i++] = li;
 
+	item_compare_func_err = FALSE;
 	/* test the compare function */
 	if (item_compare_func != NULL
 		&& item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
@@ -12699,11 +13064,14 @@ f_sort(argvars, rettv)
 	    qsort((void *)ptrs, (size_t)len, sizeof(listitem_T *),
 		    item_compare_func == NULL ? item_compare : item_compare2);
 
-	    /* Clear the List and append the items in the sorted order. */
-	    l->lv_first = l->lv_last = NULL;
-	    l->lv_len = 0;
-	    for (i = 0; i < len; ++i)
-		list_append(l, ptrs[i]);
+	    if (!item_compare_func_err)
+	    {
+		/* Clear the List and append the items in the sorted order. */
+		l->lv_first = l->lv_last = NULL;
+		l->lv_len = 0;
+		for (i = 0; i < len; ++i)
+		    list_append(l, ptrs[i]);
+	    }
 	}
 
 	vim_free(ptrs);
@@ -12726,6 +13094,7 @@ f_split(argvars, rettv)
     list_T	*l;
     colnr_T	col = 0;
     int		keepempty = FALSE;
+    int		typeerr = FALSE;
 
     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
     save_cpo = p_cpo;
@@ -12734,9 +13103,11 @@ f_split(argvars, rettv)
     str = get_tv_string(&argvars[0]);
     if (argvars[1].v_type != VAR_UNKNOWN)
     {
-	pat = get_tv_string_buf(&argvars[1], patbuf);
+	pat = get_tv_string_buf_chk(&argvars[1], patbuf);
+	if (pat == NULL)
+	    typeerr = TRUE;
 	if (argvars[2].v_type != VAR_UNKNOWN)
-	    keepempty = get_tv_number(&argvars[2]);
+	    keepempty = get_tv_number_chk(&argvars[2], &typeerr);
     }
     if (pat == NULL || *pat == NUL)
 	pat = (char_u *)"[\\x01- ]\\+";
@@ -12747,6 +13118,8 @@ f_split(argvars, rettv)
     rettv->v_type = VAR_LIST;
     rettv->vval.v_list = l;
     ++l->lv_refcount;
+    if (typeerr)
+	return;
 
     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
     if (regmatch.regprog != NULL)
@@ -12873,14 +13246,18 @@ f_stridx(argvars, rettv)
     char_u	*pos;
     int		start_idx;
 
-    needle = get_tv_string(&argvars[1]);
-    save_haystack = haystack = get_tv_string_buf(&argvars[0], buf);
+    needle = get_tv_string_chk(&argvars[1]);
+    save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
     rettv->vval.v_number = -1;
+    if (needle == NULL || haystack == NULL)
+	return;		/* type error; errmsg already given */
 
     if (argvars[2].v_type != VAR_UNKNOWN)
     {
-	start_idx = get_tv_number(&argvars[2]);
-	if (start_idx >= (int)STRLEN(haystack))
+	int	    error = FALSE;
+
+	start_idx = get_tv_number_chk(&argvars[2], &error);
+	if (error || start_idx >= (int)STRLEN(haystack))
 	    return;
 	if (start_idx >= 0)
 	    haystack += start_idx;
@@ -12932,12 +13309,15 @@ f_strpart(argvars, rettv)
     int		n;
     int		len;
     int		slen;
+    int		error = FALSE;
 
     p = get_tv_string(&argvars[0]);
     slen = (int)STRLEN(p);
 
-    n = get_tv_number(&argvars[1]);
-    if (argvars[2].v_type != VAR_UNKNOWN)
+    n = get_tv_number_chk(&argvars[1], &error);
+    if (error)
+	len = 0;
+    else if (argvars[2].v_type != VAR_UNKNOWN)
 	len = get_tv_number(&argvars[2]);
     else
 	len = slen - n;	    /* default len: all bytes that are available. */
@@ -12977,19 +13357,19 @@ f_strridx(argvars, rettv)
     char_u	*lastmatch = NULL;
     int		haystack_len, end_idx;
 
-    needle = get_tv_string(&argvars[1]);
-    haystack = get_tv_string_buf(&argvars[0], buf);
+    needle = get_tv_string_chk(&argvars[1]);
+    haystack = get_tv_string_buf_chk(&argvars[0], buf);
     haystack_len = STRLEN(haystack);
+
+    rettv->vval.v_number = -1;
+    if (needle == NULL || haystack == NULL)
+	return;		/* type error; errmsg already given */
     if (argvars[2].v_type != VAR_UNKNOWN)
     {
 	/* Third argument: upper limit for index */
-	end_idx = get_tv_number(&argvars[2]);
+	end_idx = get_tv_number_chk(&argvars[2], NULL);
 	if (end_idx < 0)
-	{
-	    /* can never find a match */
-	    rettv->vval.v_number = -1;
-	    return;
-	}
+	    return;	/* can never find a match */
     }
     else
 	end_idx = haystack_len;
@@ -13037,7 +13417,8 @@ f_submatch(argvars, rettv)
     typval_T	*rettv;
 {
     rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = reg_submatch((int)get_tv_number(&argvars[0]));
+    rettv->vval.v_string =
+		    reg_submatch((int)get_tv_number_chk(&argvars[0], NULL));
 }
 
 /*
@@ -13052,12 +13433,16 @@ f_substitute(argvars, rettv)
     char_u	subbuf[NUMBUFLEN];
     char_u	flagsbuf[NUMBUFLEN];
 
+    char_u	*str = get_tv_string_chk(&argvars[0]);
+    char_u	*pat = get_tv_string_buf_chk(&argvars[1], patbuf);
+    char_u	*sub = get_tv_string_buf_chk(&argvars[2], subbuf);
+    char_u	*flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
+
     rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = do_string_sub(
-	    get_tv_string(&argvars[0]),
-	    get_tv_string_buf(&argvars[1], patbuf),
-	    get_tv_string_buf(&argvars[2], subbuf),
-	    get_tv_string_buf(&argvars[3], flagsbuf));
+    if (str == NULL || pat == NULL || sub == NULL || flg == NULL)
+	rettv->vval.v_string = NULL;
+    else
+	rettv->vval.v_string = do_string_sub(str, pat, sub, flg);
 }
 
 /*
@@ -13074,12 +13459,13 @@ f_synID(argvars, rettv)
     long	lnum;
     long	col;
     int		trans;
-
-    lnum = get_tv_lnum(argvars);
-    col = get_tv_number(&argvars[1]) - 1;
-    trans = get_tv_number(&argvars[2]);
-
-    if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
+    int		transerr;
+
+    lnum = get_tv_lnum(argvars);		/* -1 on type error */
+    col = get_tv_number(&argvars[1]) - 1;	/* -1 on type error */
+    trans = get_tv_number_chk(&argvars[2], &transerr);
+
+    if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
 	    && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
 	id = syn_get_id(lnum, (colnr_T)col, trans, NULL);
 #endif
@@ -13236,7 +13622,9 @@ f_system(argvars, rettv)
 	    EMSG2(_(e_notopen), infile);
 	    goto done;
 	}
-	p = get_tv_string_buf(&argvars[1], buf);
+	p = get_tv_string_buf_chk(&argvars[1], buf);
+	if (p == NULL)
+	    goto done;		/* type error; errmsg already given */
 	if (fwrite(p, STRLEN(p), 1, fd) != 1)
 	    err = TRUE;
 	if (fclose(fd) != 0)
@@ -13305,6 +13693,8 @@ f_taglist(argvars, rettv)
     tag_pattern = get_tv_string(&argvars[0]);
 
     rettv->vval.v_number = FALSE;
+    if (*tag_pattern == NUL)
+	return;
 
     l = list_alloc();
     if (l != NULL)
@@ -13407,39 +13797,8 @@ f_toupper(argvars, rettv)
     typval_T	*argvars;
     typval_T	*rettv;
 {
-    char_u	*p;
-
-    p = vim_strsave(get_tv_string(&argvars[0]));
     rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = p;
-
-    if (p != NULL)
-	while (*p != NUL)
-	{
-#ifdef FEAT_MBYTE
-	    int		l;
-
-	    if (enc_utf8)
-	    {
-		int c, uc;
-
-		c = utf_ptr2char(p);
-		uc = utf_toupper(c);
-		l = utf_ptr2len_check(p);
-		/* TODO: reallocate string when byte count changes. */
-		if (utf_char2len(uc) == l)
-		    utf_char2bytes(uc, p);
-		p += l;
-	    }
-	    else if (has_mbyte && (l = (*mb_ptr2len_check)(p)) > 1)
-		p += l;		/* skip multi-byte character */
-	    else
-#endif
-	    {
-		*p = TOUPPER_LOC(*p); /* note that toupper() can be a macro */
-		p++;
-	    }
-	}
+    rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
 }
 
 /*
@@ -13468,12 +13827,14 @@ f_tr(argvars, rettv)
     garray_T	ga;
 
     instr = get_tv_string(&argvars[0]);
-    fromstr = get_tv_string_buf(&argvars[1], buf);
-    tostr = get_tv_string_buf(&argvars[2], buf2);
+    fromstr = get_tv_string_buf_chk(&argvars[1], buf);
+    tostr = get_tv_string_buf_chk(&argvars[2], buf2);
 
     /* Default return value: empty string. */
     rettv->v_type = VAR_STRING;
     rettv->vval.v_string = NULL;
+    if (fromstr == NULL || tostr == NULL)
+	    return;		/* type error; errmsg already given */
     ga_init2(&ga, (int)sizeof(char), 80);
 
 #ifdef FEAT_MBYTE
@@ -13718,8 +14079,10 @@ f_winnr(argvars, rettv)
 
     if (argvars[0].v_type != VAR_UNKNOWN)
     {
-	arg = get_tv_string(&argvars[0]);
-	if (STRCMP(arg, "$") == 0)
+	arg = get_tv_string_chk(&argvars[0]);
+	if (arg == NULL)
+	    nr = 0;		/* type error; errmsg already given */
+	else if (STRCMP(arg, "$") == 0)
 	    twin = lastwin;
 	else if (STRCMP(arg, "#") == 0)
 	{
@@ -13806,9 +14169,11 @@ find_win_by_nr(vp)
 #endif
     int		nr;
 
-    nr = get_tv_number(vp);
+    nr = get_tv_number_chk(vp, NULL);
 
 #ifdef FEAT_WINDOWS
+    if (nr < 0)
+	return NULL;
     if (nr == 0)
 	return curwin;
 
@@ -13906,7 +14271,9 @@ var2fpos(varp, lnum)
     static pos_T	pos;
     pos_T	*pp;
 
-    name = get_tv_string(varp);
+    name = get_tv_string_chk(varp);
+    if (name == NULL)
+	return NULL;
     if (name[0] == '.')		/* cursor */
 	return &curwin->w_cursor;
     if (name[0] == '\'')	/* mark */
@@ -14621,18 +14988,31 @@ init_tv(varp)
 /*
  * Get the number value of a variable.
  * If it is a String variable, uses vim_str2nr().
+ * For incompatible types, return 0.
+ * get_tv_number_chk() is similar to get_tv_number(), but informs the
+ * caller of incompatible types: it sets *denote to TRUE if "denote"
+ * is not NULL or returns -1 otherwise.
  */
     static long
 get_tv_number(varp)
     typval_T	*varp;
 {
+    int		error = FALSE;
+
+    return get_tv_number_chk(varp, &error);	/* return 0L on error */
+}
+
+    static long
+get_tv_number_chk(varp, denote)
+    typval_T	*varp;
+    int		*denote;
+{
     long	n = 0L;
 
     switch (varp->v_type)
     {
 	case VAR_NUMBER:
-	    n = (long)(varp->vval.v_number);
-	    break;
+	    return (long)(varp->vval.v_number);
 	case VAR_FUNC:
 	    EMSG(_("E703: Using a Funcref as a number"));
 	    break;
@@ -14640,7 +15020,7 @@ get_tv_number(varp)
 	    if (varp->vval.v_string != NULL)
 		vim_str2nr(varp->vval.v_string, NULL, NULL,
 							TRUE, TRUE, &n, NULL);
-	    break;
+	    return n;
 	case VAR_LIST:
 	    EMSG(_("E745: Using a List as a number"));
 	    break;
@@ -14651,11 +15031,16 @@ get_tv_number(varp)
 	    EMSG2(_(e_intern2), "get_tv_number()");
 	    break;
     }
+    if (denote == NULL)		/* useful for values that must be unsigned */
+	n = -1;
+    else
+	*denote = TRUE;
     return n;
 }
 
 /*
  * Get the lnum from the first argument.  Also accepts ".", "$", etc.
+ * Returns -1 on error.
  */
     static linenr_T
 get_tv_lnum(argvars)
@@ -14664,7 +15049,7 @@ get_tv_lnum(argvars)
     typval_T	rettv;
     linenr_T	lnum;
 
-    lnum = get_tv_number(&argvars[0]);
+    lnum = get_tv_number_chk(&argvars[0], NULL);
     if (lnum == 0)  /* no valid number, try using line() */
     {
 	rettv.v_type = VAR_NUMBER;
@@ -14682,6 +15067,8 @@ get_tv_lnum(argvars)
  * get_tv_string_buf() uses a given buffer.
  * If the String variable has never been set, return an empty string.
  * Never returns NULL;
+ * get_tv_string_chk() and get_tv_string_buf_chk() are similar, but return
+ * NULL on error.
  */
     static char_u *
 get_tv_string(varp)
@@ -14697,6 +15084,25 @@ get_tv_string_buf(varp, buf)
     typval_T	*varp;
     char_u	*buf;
 {
+    char_u	*res =  get_tv_string_buf_chk(varp, buf);
+
+    return res != NULL ? res : (char_u *)"";
+}
+
+    static char_u *
+get_tv_string_chk(varp)
+    typval_T	*varp;
+{
+    static char_u   mybuf[NUMBUFLEN];
+
+    return get_tv_string_buf_chk(varp, mybuf);
+}
+
+    static char_u *
+get_tv_string_buf_chk(varp, buf)
+    typval_T	*varp;
+    char_u	*buf;
+{
     switch (varp->v_type)
     {
 	case VAR_NUMBER:
@@ -14714,12 +15120,12 @@ get_tv_string_buf(varp, buf)
 	case VAR_STRING:
 	    if (varp->vval.v_string != NULL)
 		return varp->vval.v_string;
-	    break;
+	    return (char_u *)"";
 	default:
 	    EMSG2(_(e_intern2), "get_tv_string_buf()");
 	    break;
     }
-    return (char_u *)"";
+    return NULL;
 }
 
 /*