[vim/vim] Type safety issue with `legacy call map()` or `legacy let` breaking a Vim9 script variable's declared type (Issue #18531)

3 views
Skip to first unread message

Peter Kenny

unread,
Oct 9, 2025, 4:31:44 PM (yesterday) Oct 9
to vim/vim, Subscribed
kennypete created an issue (vim/vim#18531)

The following script shows a dict<number> allowing string values after a legacy call map(). It still reports as as dict<number>, despite containing strings. At the script level, legacy let can add an invalid type to the dictionary too:

vim9script

echo "---- myDict is type dict<number> ----"
var myDict: dict<number> = {'one': 1, 'two': 2}
echo myDict
echo myDict->typename()

echo "\n---- myDict containing strings ----"

def BreakMyDict()
    legacy call map(s:myDict, {i -> $"item {i}"})
enddef
BreakMyDict()
echo $"myDict is now {myDict}"
echo myDict->typename()
echo myDict['one']->typename()
echo myDict['two']->typename()

echo "\n---- myDict containing any ----"

legacy let s:myDict['two'] = (2, )
echo $"myDict is now {myDict}"
echo myDict->typename()
echo myDict['one']->typename()
echo myDict['two']->typename()
image.png (view on web)
# " This undermines Vim9 script's type safety guarantees.
# " Code relying on declared types fails unexpectedly.
# " Since `typename()` reports incorrect information, even runtime
# " type checking does not detect the type mismatch
# " E.g., Later in code, presuming dict<number> is safe ...
if myDict->typename() == 'dict<number>'
  # " Yes, sure is ...
  try
    var mySum: number = myDict['one'] + 1 
  catch
    echo v:exception
    # " E1030: Using String as a Number
  endtry
  try
    var mySum: number = 1 + myDict['two']
  catch
    echo v:exception
    # " E1520: Using Tuple as a Number
  endtry
endif

Version 9.1 w/ 1833


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/18531@github.com>

Reply all
Reply to author
Forward
0 new messages