patch 9.0.0430: cannot use repeat() with a blob

Problem:    Cannot use repeat() with a blob.
Solution:   Implement blob repeat. (closes #11090)
diff --git a/src/errors.h b/src/errors.h
index 2ed62a2..45f0d6a 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -3329,4 +3329,6 @@
 #ifdef FEAT_EVAL
 EXTERN char e_cannot_use_partial_with_dictionary_for_defer[]
 	INIT(= N_("E1300: Cannot use a partial with dictionary for :defer"));
+EXTERN char e_string_number_list_or_blob_required_for_argument_nr[]
+	INIT(= N_("E1301: String, Number, List or Blob required for argument %d"));
 #endif
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 2c041fa..bc0e23e 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -872,6 +872,7 @@
 	    || type->tt_type == VAR_UNKNOWN
 	    || type->tt_type == VAR_STRING
 	    || type->tt_type == VAR_NUMBER
+	    || type->tt_type == VAR_BLOB
 	    || type->tt_type == VAR_LIST)
 	return OK;
 
@@ -4400,6 +4401,10 @@
 #endif
 }
 
+/*
+ * "function()" function
+ * "funcref()" function
+ */
     static void
 common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
 {
@@ -8399,18 +8404,19 @@
 f_repeat(typval_T *argvars, typval_T *rettv)
 {
     char_u	*p;
-    int		n;
+    varnumber_T	n;
     int		slen;
     int		len;
     char_u	*r;
     int		i;
 
     if (in_vim9script()
-	    && (check_for_string_or_number_or_list_arg(argvars, 0) == FAIL
+	    && (check_for_string_or_number_or_list_or_blob_arg(argvars, 0)
+		    == FAIL
 		|| check_for_number_arg(argvars, 1) == FAIL))
 	return;
 
-    n = (int)tv_get_number(&argvars[1]);
+    n = tv_get_number(&argvars[1]);
     if (argvars[0].v_type == VAR_LIST)
     {
 	if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
@@ -8419,6 +8425,35 @@
 					argvars[0].vval.v_list, NULL) == FAIL)
 		    break;
     }
+    else if (argvars[0].v_type == VAR_BLOB)
+    {
+	if (rettv_blob_alloc(rettv) == FAIL
+		|| argvars[0].vval.v_blob == NULL
+		|| n <= 0)
+	    return;
+
+	slen = argvars[0].vval.v_blob->bv_ga.ga_len;
+	len = (int)slen * n;
+	if (len <= 0)
+	    return;
+
+	if (ga_grow(&rettv->vval.v_blob->bv_ga, len) == FAIL)
+	    return;
+
+	rettv->vval.v_blob->bv_ga.ga_len = len;
+
+	for (i = 0; i < slen; ++i)
+	    if (blob_get(argvars[0].vval.v_blob, i) != 0)
+		break;
+
+	if (i == slen)
+	    // No need to copy since all bytes are already zero
+	    return;
+
+	for (i = 0; i < n; ++i)
+	    blob_set_range(rettv->vval.v_blob,
+		    (long)i * slen, ((long)i + 1) * slen - 1, argvars);
+    }
     else
     {
 	p = tv_get_string(&argvars[0]);
diff --git a/src/proto/typval.pro b/src/proto/typval.pro
index 7d32a03..b4733fd 100644
--- a/src/proto/typval.pro
+++ b/src/proto/typval.pro
@@ -42,6 +42,7 @@
 int check_for_string_or_dict_arg(typval_T *args, int idx);
 int check_for_string_or_number_or_list_arg(typval_T *args, int idx);
 int check_for_opt_string_or_number_or_list_arg(typval_T *args, int idx);
+int check_for_string_or_number_or_list_or_blob_arg(typval_T *args, int idx);
 int check_for_string_or_list_or_dict_arg(typval_T *args, int idx);
 int check_for_string_or_func_arg(typval_T *args, int idx);
 int check_for_list_or_blob_arg(typval_T *args, int idx);
diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim
index 46370c4..b0239fd 100644
--- a/src/testdir/test_blob.vim
+++ b/src/testdir/test_blob.vim
@@ -725,6 +725,18 @@
   call assert_equal(v, string(b))
 endfunc
 
+func Test_blob_repeat()
+  call assert_equal(0z, repeat(0z00, 0))
+  call assert_equal(0z00, repeat(0z00, 1))
+  call assert_equal(0z0000, repeat(0z00, 2))
+  call assert_equal(0z00000000, repeat(0z0000, 2))
+
+  call assert_equal(0z, repeat(0z12, 0))
+  call assert_equal(0z, repeat(0z1234, 0))
+  call assert_equal(0z1234, repeat(0z1234, 1))
+  call assert_equal(0z12341234, repeat(0z1234, 2))
+endfunc
+
 " Test for blob allocation failure
 func Test_blob_alloc_failure()
   " blob variable
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index b74a8ec..109cb35 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -3329,12 +3329,14 @@
 enddef
 
 def Test_repeat()
-  v9.CheckDefAndScriptFailure(['repeat(1.1, 2)'], ['E1013: Argument 1: type mismatch, expected string but got float', 'E1224: String, Number or List required for argument 1'])
-  v9.CheckDefAndScriptFailure(['repeat({a: 10}, 2)'], ['E1013: Argument 1: type mismatch, expected string but got dict<', 'E1224: String, Number or List required for argument 1'])
+  v9.CheckDefAndScriptFailure(['repeat(1.1, 2)'], ['E1013: Argument 1: type mismatch, expected string but got float', 'E1301: String, Number, List or Blob required for argument 1'])
+  v9.CheckDefAndScriptFailure(['repeat({a: 10}, 2)'], ['E1013: Argument 1: type mismatch, expected string but got dict<', 'E1301: String, Number, List or Blob required for argument 1'])
   var lines =<< trim END
       assert_equal('aaa', repeat('a', 3))
       assert_equal('111', repeat(1, 3))
       assert_equal([1, 1, 1], repeat([1], 3))
+      assert_equal(0z000102000102000102, repeat(0z000102, 3))
+      assert_equal(0z000000, repeat(0z00, 3))
       var s = '-'
       s ..= repeat(5, 3)
       assert_equal('-555', s)
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index c616e18..fce215e 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -2534,6 +2534,12 @@
   res->assert_equal(3)
 
   res = 0
+  for n in repeat(0z01, 3)->blob2list()
+    res += n
+  endfor
+  res->assert_equal(3)
+
+  res = 0
   for n in add([1, 2], 3)
     res += n
   endfor
diff --git a/src/typval.c b/src/typval.c
index 12a741e..95abe21 100644
--- a/src/typval.c
+++ b/src/typval.c
@@ -792,6 +792,24 @@
 }
 
 /*
+ * Give an error and return FAIL unless "args[idx]" is a string or a number
+ * or a list or a blob.
+ */
+    int
+check_for_string_or_number_or_list_or_blob_arg(typval_T *args, int idx)
+{
+    if (args[idx].v_type != VAR_STRING
+	    && args[idx].v_type != VAR_NUMBER
+	    && args[idx].v_type != VAR_LIST
+	    && args[idx].v_type != VAR_BLOB)
+    {
+	semsg(_(e_string_number_list_or_blob_required_for_argument_nr), idx + 1);
+	return FAIL;
+    }
+    return OK;
+}
+
+/*
  * Give an error and return FAIL unless "args[idx]" is a string or a list
  * or a dict.
  */
diff --git a/src/version.c b/src/version.c
index ef5f102..3b02a3b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    430,
+/**/
     429,
 /**/
     428,