Skip to content

Comments

fix: typename() returns wrong type for lists/dicts/tuples with shared references#19492

Closed
h-east wants to merge 1 commit intovim:masterfrom
h-east:typename-returns-wrong-type-with-repeat
Closed

fix: typename() returns wrong type for lists/dicts/tuples with shared references#19492
h-east wants to merge 1 commit intovim:masterfrom
h-east:typename-returns-wrong-type-with-repeat

Conversation

@h-east
Copy link
Member

@h-east h-east commented Feb 23, 2026

Fixes: #19490

Problem

typename() incorrectly returned list for the member type when a container
held multiple references to the same inner object. For example:

echo [[" "]]->repeat(3)->typename()   " returned list<list<any>>, expected list<list<string>>

repeat() makes all elements point to the same inner list/dict/tuple object
(shallow copy via copy_tv()). During type inference, list_typval2type(),
dict_typval2type(), and tuple_typval2type() use a copyID to guard against
infinite recursion on circular references. However, they never cleared the
copyID after finishing, so when the same object was encountered again as a
sibling element (a shared reference, not a circular one), it was mistakenly
treated as a circular reference and t_list_any / t_dict_any / t_tuple_any was
returned.

Solution

Reset lv_copyID / dv_copyID / tv_copyID to 0 after all members have been
processed in each of the three functions. The circular reference guard still
works correctly because the copyID is set before processing members and only
cleared after — so any re-entrant call on the same object during its own
traversal is still detected and short-circuits with t_*_any.

@h-east h-east requested a review from yegappan February 23, 2026 21:38
@mao-yining
Copy link
Contributor

mao-yining commented Feb 24, 2026

The document didn’t describe that how repeat() deal with a list within a list. Would it be more sensible to use copy() or deepcopy(), or just add a note to the documentation?

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a bug where typename() incorrectly returned list<any>, dict<any>, or tuple<any> for containers with shared (non-circular) references to inner objects. The issue occurred when functions like repeat() created multiple elements pointing to the same inner object, causing the copyID mechanism (used to detect circular references) to incorrectly treat shared references as circular.

Changes:

  • Added copyID reset logic in list_typval2type(), tuple_typval2type(), and dict_typval2type() functions
  • Added comprehensive tests for circular references and shared references for lists, dicts, and tuples

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/vim9type.c Resets copyID to 0 after processing container members in three type inference functions to distinguish shared references from circular references
src/testdir/test_vim9_builtin.vim Adds tests for circular references and shared references in lists and dicts using typename()
src/testdir/test_tuple.vim Adds tests for shared references in tuples using typename()

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chrisbra
Copy link
Member

thanks

@chrisbra chrisbra closed this in b1d4b03 Feb 24, 2026
@h-east h-east deleted the typename-returns-wrong-type-with-repeat branch February 25, 2026 00:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

typename() return incorrect value as the method of repeat()

3 participants