Open errael opened 1 year ago
When you assign null_list to the variable l
, the type of l
changes to the type of null_list (which is list
var l: list<number> = [1, 2, 3]
l = []
echo typename(l)
When you assign null_list to the variable
l
, the type ofl
changes to the type of null_list (which is list). To retain the variable type, but remove the list, you can assign it to an empty list.var l: list<number> = [1, 2, 3] l = [] echo typename(l)
Note that you get this errror
l: list<number>
l: list<unknown>
Error detected while processing :source buffer=1:
line 12:
E1012: Type mismatch; expected list<number> but got list<string>
from
vim9script
class C
endclass
var l: list<number>
echo 'l:' typename(l)
l = null_list
echo 'l:' typename(l)
l = ['a']
So l
does retain the type even as a null_list
. The behavior we see, not outputting the correct type information, seems more an implementation artifact that has leaked into programmer visible space.
Assigning []
is not viable; I have code where an empty list is different from a null list.
[This is an unworkable solution]
typename()
takes an expression, internally a typval_T
. The current implementation of a null typval_T
has no member type information, like list<number>
vs list<string>
. This issue only affects list
/dict
(I think).
In the discussion assume we're dealing with a list.
Here's a possibility on how this issue could be fixed in steps.
is_null_tv(typeval_T*)
function/macro/inline.
Use this everywhere that a typval_T
is checked to see if it is a null. (Only really needed for dict/list)typval_T
, V_NULL
.
When set the value is null
and there may be type information.V_NULL
as possible.
For this case, when a variable is evaluated and the result is null, instead of setting v_list
to null set it to an empty list and use/clone the type info from the variable.V_NULL
as needed.If there is interest, I'll look at doing this. See below for details/caveats; and it may turn out to be much more difficult or far reaching than anticipated.
Curiously, this is also related to the gazillion null types. If this is implemented, it's more than half way (I think) to a solution to get rid of the plethora of null types, see https://github.com/vim/vim/discussions/13458#discussioncomment-7440006. I do not know if this proposal presents problems relating the current use of "null types".
As with some other issues this one is related to using a builtin function to do something which should be handled as part of the language.
Notes and details of interest to geeks and/or implementers.
I believe this problem only relates to list
or dict
(and possibly function
) because they have a lv_type
/dv_type
type_S
has tt_member
for item type. So (1), (2) only needed for list
/dict
. This means that checks for null value where the item is not a list/dict, e.g. it's a job
, do not need to use is_null_tv()
, but for uniformity...
The proposal(hack), set a flag in typval_T
that means "is_null", and then have an empty list (instead of NULL pointer) that has the complete type information. This would mean that the code that checks if something is null would do
if ((tv->flags & V_NULL) != 0) // true if null value
instead of
if (tv->vval.v_list == NULL) // true if null value
but would do in some/most situations (at least during a transition period)
if ((tv->flags & V_NULL) != 0 || tv->vval.v_list == NULL)
The idea is that you could do
if ((tv->flags & V_NULL) != 0 || tv->vval.v_list == NULL)
{
if (tv->vval.v_list != NULL)
{
// use the typeinfo associated with the null item.
}
}
A singleton/read-only empty-list would be ideal to use for this, but that may not be possible because something might want to reference count it. Note: there is currently no flags field in typeval_T, but one can be added without increasing the size of the struct (think that's true for all CPU arch).
Notice that there's
actual_type = typval2type(actual_tv, get_copyID(), &type_list,
TVTT_DO_MEMBER | TVTT_MORE_SPECIFIC);
That'll be something interesting to take a look at; including where/how it is used.
NOTE: for this to work, every spot where there's a check for a null vim thing it would need to use is_null_tv(typeval_T*)
(for list/dict anyway); once that's in place the V_NULL
flag could be used.
Could be a good place to use inline int is_tv_null(typval_T*)
. I don't know what's
acceptable here for vim, might need
#ifdef INLINE_OK
inline int is_tv_null(typval_T*)
#else
#define is_tv_null(x) xxxwhateverxxx
#endif
Or just make it a function and accept the hit.
typename()
takes an expression, internally a typval_T
. The current implementation of a null typval_T
has no member type information, like list<number>
vs list<string>
. This issue only affects list
/dict
(I think).
A solution could involve saving argument information that can be examined by a builtin function.
May be related to #13696
Steps to reproduce
This output
is generated by the following script
Expected behaviour
Correct/consistent type information.
Version of Vim
9.0.2077
Environment
ubuntu
Logs and stack traces
No response