patch 8.2.3848: cannot use reduce() for a string
Problem: Cannot use reduce() for a string.
Solution: Make reduce() work with a string. (Naruhiko Nishino, closes #9366)
diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim
index 30f47ad..c767313 100644
--- a/src/testdir/test_listdict.vim
+++ b/src/testdir/test_listdict.vim
@@ -1,4 +1,5 @@
" Tests for the List and Dict types
+scriptencoding utf-8
source vim9.vim
@@ -936,7 +937,7 @@
call assert_fails("call sort([1, 2], function('min'))", "E118:")
endfunc
-" reduce a list or a blob
+" reduce a list, blob or string
func Test_reduce()
let lines =<< trim END
call assert_equal(1, reduce([], LSTART acc, val LMIDDLE acc + val LEND, 1))
@@ -959,6 +960,16 @@
call assert_equal(0xff, reduce(0zff, LSTART acc, val LMIDDLE acc + val LEND))
call assert_equal(2 * (2 * 0xaf + 0xbf) + 0xcf, reduce(0zAFBFCF, LSTART acc, val LMIDDLE 2 * acc + val LEND))
+
+ call assert_equal('x,y,z', 'xyz'->reduce(LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
+ call assert_equal('', ''->reduce(LSTART acc, val LMIDDLE acc .. ',' .. val LEND, ''))
+ call assert_equal('あ,い,う,え,お,😊,💕', 'あいうえお😊💕'->reduce(LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
+ call assert_equal('😊,あ,い,う,え,お,💕', 'あいうえお💕'->reduce(LSTART acc, val LMIDDLE acc .. ',' .. val LEND, '😊'))
+ call assert_equal('ऊ,ॠ,ॡ', reduce('ऊॠॡ', LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
+ call assert_equal('c,à,t', reduce('càt', LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
+ call assert_equal('Å,s,t,r,ö,m', reduce('Åström', LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
+ call assert_equal('Å,s,t,r,ö,m', reduce('Åström', LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
+ call assert_equal(',a,b,c', reduce('abc', LSTART acc, val LMIDDLE acc .. ',' .. val LEND, test_null_string()))
END
call CheckLegacyAndVim9Success(lines)
@@ -967,13 +978,23 @@
call assert_fails("call reduce([], { acc, val -> acc + val })", 'E998: Reduce of an empty List with no initial value')
call assert_fails("call reduce(0z, { acc, val -> acc + val })", 'E998: Reduce of an empty Blob with no initial value')
+ call assert_fails("call reduce('', { acc, val -> acc + val })", 'E998: Reduce of an empty String with no initial value')
+ call assert_fails("call reduce(test_null_string(), { acc, val -> acc + val })", 'E998: Reduce of an empty String with no initial value')
- call assert_fails("call reduce({}, { acc, val -> acc + val }, 1)", 'E897:')
- call assert_fails("call reduce(0, { acc, val -> acc + val }, 1)", 'E897:')
- call assert_fails("call reduce('', { acc, val -> acc + val }, 1)", 'E897:')
+ call assert_fails("call reduce({}, { acc, val -> acc + val }, 1)", 'E1098:')
+ call assert_fails("call reduce(0, { acc, val -> acc + val }, 1)", 'E1098:')
call assert_fails("call reduce([1, 2], 'Xdoes_not_exist')", 'E117:')
call assert_fails("echo reduce(0z01, { acc, val -> 2 * acc + val }, '')", 'E39:')
+ call assert_fails("vim9 reduce(0, (acc, val) => (acc .. val), '')", 'E1252:')
+ call assert_fails("vim9 reduce({}, (acc, val) => (acc .. val), '')", 'E1252:')
+ call assert_fails("vim9 reduce(0.1, (acc, val) => (acc .. val), '')", 'E1252:')
+ call assert_fails("vim9 reduce(function('tr'), (acc, val) => (acc .. val), '')", 'E1252:')
+ call assert_fails("call reduce('', { acc, val -> acc + val }, 1)", 'E1253:')
+ call assert_fails("call reduce('', { acc, val -> acc + val }, {})", 'E1253:')
+ call assert_fails("call reduce('', { acc, val -> acc + val }, 0.1)", 'E1253:')
+ call assert_fails("call reduce('', { acc, val -> acc + val }, function('tr'))", 'E1253:')
+
let g:lut = [1, 2, 3, 4]
func EvilRemove()
call remove(g:lut, 1)
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index aa5af0d..a6d8984 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -1232,7 +1232,7 @@
enddef
def Test_filter()
- CheckDefAndScriptFailure2(['filter(1.1, "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got float', 'E1228: List, Dictionary, Blob or String required for argument 1')
+ CheckDefAndScriptFailure2(['filter(1.1, "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got float', 'E1251: List, Dictionary, Blob or String required for argument 1')
assert_equal([], filter([1, 2, 3], '0'))
assert_equal([1, 2, 3], filter([1, 2, 3], '1'))
assert_equal({b: 20}, filter({a: 10, b: 20}, 'v:val == 20'))
@@ -2028,9 +2028,9 @@
def Test_map()
if has('channel')
- CheckDefAndScriptFailure2(['map(test_null_channel(), "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got channel', 'E1228: List, Dictionary, Blob or String required for argument 1')
+ CheckDefAndScriptFailure2(['map(test_null_channel(), "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got channel', 'E1251: List, Dictionary, Blob or String required for argument 1')
endif
- CheckDefAndScriptFailure2(['map(1, "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got number', 'E1228: List, Dictionary, Blob or String required for argument 1')
+ CheckDefAndScriptFailure2(['map(1, "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got number', 'E1251: List, Dictionary, Blob or String required for argument 1')
enddef
def Test_map_failure()
@@ -2147,9 +2147,9 @@
def Test_mapnew()
if has('channel')
- CheckDefAndScriptFailure2(['mapnew(test_null_job(), "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got job', 'E1228: List, Dictionary, Blob or String required for argument 1')
+ CheckDefAndScriptFailure2(['mapnew(test_null_job(), "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got job', 'E1251: List, Dictionary, Blob or String required for argument 1')
endif
- CheckDefAndScriptFailure2(['mapnew(1, "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got number', 'E1228: List, Dictionary, Blob or String required for argument 1')
+ CheckDefAndScriptFailure2(['mapnew(1, "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got number', 'E1251: List, Dictionary, Blob or String required for argument 1')
enddef
def Test_mapset()
@@ -2682,7 +2682,7 @@
enddef
def Test_reduce()
- CheckDefAndScriptFailure2(['reduce({a: 10}, "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got dict<number>', 'E897: List or Blob required')
+ CheckDefAndScriptFailure2(['reduce({a: 10}, "1")'], 'E1013: Argument 1: type mismatch, expected list<any> but got dict<number>', 'E1252: String, List or Blob required for argument 1')
assert_equal(6, [1, 2, 3]->reduce((r, c) => r + c, 0))
assert_equal(11, 0z0506->reduce((r, c) => r + c, 0))
enddef