comparison src/testdir/test_iminsert.vim @ 26518:13ba00ef7687 v8.2.3788

patch 8.2.3788: lambda for option that is a function may be freed Commit: https://github.com/vim/vim/commit/6ae8fae8696623b527c7fb22567f6a3705b2f0dd Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Sun Dec 12 16:26:44 2021 +0000 patch 8.2.3788: lambda for option that is a function may be freed Problem: Lambda for option that is a function may be garbage collected. Solution: Set a reference in the funcref. (Yegappan Lakshmanan, closes #9330)
author Bram Moolenaar <Bram@vim.org>
date Sun, 12 Dec 2021 17:30:04 +0100
parents 65b4109a4297
children 33d680d372aa
comparison
equal deleted inserted replaced
26517:7dfc4c45f698 26518:13ba00ef7687
117 endfunc 117 endfunc
118 func IMstatusfunc1() 118 func IMstatusfunc1()
119 let g:IMstatusfunc_called += 1 119 let g:IMstatusfunc_called += 1
120 return 1 120 return 1
121 endfunc 121 endfunc
122 let g:IMactivatefunc_called = 0 122 set iminsert=2
123 let g:IMstatusfunc_called = 0 123
124 set iminsert=2 124 let lines =<< trim END
125 125 LET g:IMactivatefunc_called = 0
126 " Test for using a function() 126 LET g:IMstatusfunc_called = 0
127 set imactivatefunc=function('IMactivatefunc1') 127
128 set imstatusfunc=function('IMstatusfunc1') 128 #" Test for using a function()
129 normal! i 129 set imactivatefunc=function('g:IMactivatefunc1')
130 130 set imstatusfunc=function('g:IMstatusfunc1')
131 " Using a funcref variable to set 'completefunc' 131 normal! i
132 let Fn1 = function('IMactivatefunc1') 132
133 let &imactivatefunc = Fn1 133 #" Using a funcref variable to set 'completefunc'
134 let Fn2 = function('IMstatusfunc1') 134 VAR Fn1 = function('g:IMactivatefunc1')
135 let &imstatusfunc = Fn2 135 LET &imactivatefunc = Fn1
136 normal! i 136 VAR Fn2 = function('g:IMstatusfunc1')
137 137 LET &imstatusfunc = Fn2
138 " Using a string(funcref variable) to set 'completefunc' 138 normal! i
139 let &imactivatefunc = string(Fn1) 139
140 let &imstatusfunc = string(Fn2) 140 #" Using a string(funcref variable) to set 'completefunc'
141 normal! i 141 LET &imactivatefunc = string(Fn1)
142 142 LET &imstatusfunc = string(Fn2)
143 " Test for using a funcref() 143 normal! i
144 set imactivatefunc=funcref('IMactivatefunc1') 144
145 set imstatusfunc=funcref('IMstatusfunc1') 145 #" Test for using a funcref()
146 normal! i 146 set imactivatefunc=funcref('g:IMactivatefunc1')
147 147 set imstatusfunc=funcref('g:IMstatusfunc1')
148 " Using a funcref variable to set 'imactivatefunc' 148 normal! i
149 let Fn1 = funcref('IMactivatefunc1') 149
150 let &imactivatefunc = Fn1 150 #" Using a funcref variable to set 'imactivatefunc'
151 let Fn2 = funcref('IMstatusfunc1') 151 LET Fn1 = funcref('g:IMactivatefunc1')
152 let &imstatusfunc = Fn2 152 LET &imactivatefunc = Fn1
153 normal! i 153 LET Fn2 = funcref('g:IMstatusfunc1')
154 154 LET &imstatusfunc = Fn2
155 " Using a string(funcref variable) to set 'imactivatefunc' 155 normal! i
156 let &imactivatefunc = string(Fn1) 156
157 let &imstatusfunc = string(Fn2) 157 #" Using a string(funcref variable) to set 'imactivatefunc'
158 normal! i 158 LET &imactivatefunc = string(Fn1)
159 159 LET &imstatusfunc = string(Fn2)
160 " Test for using a lambda function 160 normal! i
161 set imactivatefunc={a\ ->\ IMactivatefunc1(a)} 161
162 set imstatusfunc={\ ->\ IMstatusfunc1()} 162 #" Test for using a lambda function
163 normal! i 163 VAR optval = "LSTART a LMIDDLE IMactivatefunc1(a) LEND"
164 164 LET optval = substitute(optval, ' ', '\\ ', 'g')
165 " Set 'imactivatefunc' and 'imstatusfunc' to a lambda expression 165 exe "set imactivatefunc=" .. optval
166 let &imactivatefunc = {a -> IMactivatefunc1(a)} 166 LET optval = "LSTART LMIDDLE IMstatusfunc1() LEND"
167 let &imstatusfunc = { -> IMstatusfunc1()} 167 LET optval = substitute(optval, ' ', '\\ ', 'g')
168 normal! i 168 exe "set imstatusfunc=" .. optval
169 169 normal! i
170 " Set 'imactivatefunc' and 'imstatusfunc' to a string(lambda expression) 170
171 let &imactivatefunc = '{a -> IMactivatefunc1(a)}' 171 #" Set 'imactivatefunc' and 'imstatusfunc' to a lambda expression
172 let &imstatusfunc = '{ -> IMstatusfunc1()}' 172 LET &imactivatefunc = LSTART a LMIDDLE IMactivatefunc1(a) LEND
173 normal! i 173 LET &imstatusfunc = LSTART LMIDDLE IMstatusfunc1() LEND
174 174 normal! i
175 " Set 'imactivatefunc' 'imstatusfunc' to a variable with a lambda expression 175
176 let Lambda1 = {a -> IMactivatefunc1(a)} 176 #" Set 'imactivatefunc' and 'imstatusfunc' to a string(lambda expression)
177 let Lambda2 = { -> IMstatusfunc1()} 177 LET &imactivatefunc = 'LSTART a LMIDDLE IMactivatefunc1(a) LEND'
178 let &imactivatefunc = Lambda1 178 LET &imstatusfunc = 'LSTART LMIDDLE IMstatusfunc1() LEND'
179 let &imstatusfunc = Lambda2 179 normal! i
180 normal! i 180
181 181 #" Set 'imactivatefunc' 'imstatusfunc' to a variable with a lambda
182 " Set 'imactivatefunc' 'imstatusfunc' to a string(variable with a lambda 182 #" expression
183 " expression) 183 VAR Lambda1 = LSTART a LMIDDLE IMactivatefunc1(a) LEND
184 let &imactivatefunc = string(Lambda1) 184 VAR Lambda2 = LSTART LMIDDLE IMstatusfunc1() LEND
185 let &imstatusfunc = string(Lambda2) 185 LET &imactivatefunc = Lambda1
186 normal! i 186 LET &imstatusfunc = Lambda2
187 187 normal! i
188 " Test for clearing the 'completefunc' option 188
189 set imactivatefunc='' imstatusfunc='' 189 #" Set 'imactivatefunc' 'imstatusfunc' to a string(variable with a lambda
190 set imactivatefunc& imstatusfunc& 190 #" expression)
191 191 LET &imactivatefunc = string(Lambda1)
192 call assert_fails("set imactivatefunc=function('abc')", "E700:") 192 LET &imstatusfunc = string(Lambda2)
193 call assert_fails("set imstatusfunc=function('abc')", "E700:") 193 normal! i
194 call assert_fails("set imactivatefunc=funcref('abc')", "E700:") 194
195 call assert_fails("set imstatusfunc=funcref('abc')", "E700:") 195 #" Test for clearing the 'completefunc' option
196 196 set imactivatefunc='' imstatusfunc=''
197 call assert_equal(11, g:IMactivatefunc_called) 197 set imactivatefunc& imstatusfunc&
198 call assert_equal(22, g:IMstatusfunc_called) 198
199 set imactivatefunc=g:IMactivatefunc1
200 set imstatusfunc=g:IMstatusfunc1
201 call assert_fails("set imactivatefunc=function('abc')", "E700:")
202 call assert_fails("set imstatusfunc=function('abc')", "E700:")
203 call assert_fails("set imactivatefunc=funcref('abc')", "E700:")
204 call assert_fails("set imstatusfunc=funcref('abc')", "E700:")
205 call assert_fails("LET &imstatusfunc = function('abc')", "E700:")
206 call assert_fails("LET &imactivatefunc = function('abc')", "E700:")
207 normal! i
208
209 #" set 'imactivatefunc' and 'imstatusfunc' to a non-existing function
210 set imactivatefunc=IMactivatefunc1
211 set imstatusfunc=IMstatusfunc1
212 call assert_fails("set imactivatefunc=function('NonExistingFunc')", 'E700:')
213 call assert_fails("set imstatusfunc=function('NonExistingFunc')", 'E700:')
214 call assert_fails("LET &imactivatefunc = function('NonExistingFunc')", 'E700:')
215 call assert_fails("LET &imstatusfunc = function('NonExistingFunc')", 'E700:')
216 normal! i
217
218 call assert_equal(13, g:IMactivatefunc_called)
219 call assert_equal(26, g:IMstatusfunc_called)
220 END
221 call CheckLegacyAndVim9Success(lines)
222
223 " Using Vim9 lambda expression in legacy context should fail
224 set imactivatefunc=(a)\ =>\ IMactivatefunc1(a)
225 set imstatusfunc=IMstatusfunc1
226 call assert_fails('normal! i', 'E117:')
227 set imactivatefunc=IMactivatefunc1
228 set imstatusfunc=()\ =>\ IMstatusfunc1(a)
229 call assert_fails('normal! i', 'E117:')
230
231 " set 'imactivatefunc' and 'imstatusfunc' to a partial with dict. This used
232 " to cause a crash.
233 func SetIMFunc()
234 let params1 = {'activate': function('g:DictActivateFunc')}
235 let params2 = {'status': function('g:DictStatusFunc')}
236 let &imactivatefunc = params1.activate
237 let &imstatusfunc = params2.status
238 endfunc
239 func g:DictActivateFunc(_) dict
240 endfunc
241 func g:DictStatusFunc(_) dict
242 endfunc
243 call SetIMFunc()
244 new
245 call SetIMFunc()
246 bw
247 call test_garbagecollect_now()
248 new
249 set imactivatefunc=
250 set imstatusfunc=
251 wincmd w
252 set imactivatefunc=
253 set imstatusfunc=
254 :%bw!
255 delfunc g:DictActivateFunc
256 delfunc g:DictStatusFunc
257 delfunc SetIMFunc
199 258
200 " Vim9 tests 259 " Vim9 tests
201 let lines =<< trim END 260 let lines =<< trim END
202 vim9script 261 vim9script
203 262
215 set iminsert=2 274 set iminsert=2
216 set imactivatefunc=function('IMactivatefunc1') 275 set imactivatefunc=function('IMactivatefunc1')
217 set imstatusfunc=function('IMstatusfunc1') 276 set imstatusfunc=function('IMstatusfunc1')
218 normal! i 277 normal! i
219 278
220 # Test for using a lambda
221 &imactivatefunc = '(a) => IMactivatefunc1(a)'
222 &imstatusfunc = '() => IMstatusfunc1()'
223 normal! i
224
225 # Test for using a variable with a lambda expression
226 var Fn1: func = (active) => {
227 g:IMactivatefunc_called += 1
228 return 1
229 }
230 var Fn2: func = () => {
231 g:IMstatusfunc_called += 1
232 return 1
233 }
234 &imactivatefunc = Fn1
235 &imstatusfunc = Fn2
236 normal! i
237
238 # Test for using a string(variable with a lambda expression)
239 &imactivatefunc = string(Fn1)
240 &imstatusfunc = string(Fn2)
241 normal! i
242
243 assert_equal(4, g:IMactivatefunc_called)
244 assert_equal(8, g:IMstatusfunc_called)
245
246 set iminsert=0 279 set iminsert=0
247 set imactivatefunc= 280 set imactivatefunc=
248 set imstatusfunc= 281 set imstatusfunc=
249 END 282 END
250 call CheckScriptSuccess(lines) 283 call CheckScriptSuccess(lines)
251 284
252 " Using Vim9 lambda expression in legacy context should fail
253 set imactivatefunc=(a)\ =>\ IMactivatefunc1(a)
254 set imstatusfunc=IMstatusfunc1
255 call assert_fails('normal! i', 'E117:')
256 set imactivatefunc=IMactivatefunc1
257 set imstatusfunc=()\ =>\ IMstatusfunc1(a)
258 call assert_fails('normal! i', 'E117:')
259
260 " set 'imactivatefunc' and 'imstatusfunc' to a non-existing function
261 set imactivatefunc=IMactivatefunc1
262 set imstatusfunc=IMstatusfunc1
263 call assert_fails("set imactivatefunc=function('NonExistingFunc')", 'E700:')
264 call assert_fails("set imstatusfunc=function('NonExistingFunc')", 'E700:')
265 call assert_fails("let &imactivatefunc = function('NonExistingFunc')", 'E700:')
266 call assert_fails("let &imstatusfunc = function('NonExistingFunc')", 'E700:')
267 let g:IMactivatefunc_called = 0
268 let g:IMstatusfunc_called = 0
269 normal! i
270 call assert_equal(2, g:IMactivatefunc_called)
271 call assert_equal(2, g:IMstatusfunc_called)
272
273 " cleanup 285 " cleanup
274 delfunc IMactivatefunc1 286 delfunc IMactivatefunc1
275 delfunc IMstatusfunc1 287 delfunc IMstatusfunc1
276 set iminsert=0 288 set iminsert=0
277 set imactivatefunc= 289 set imactivatefunc=