Mercurial > vim
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= |