[vim/vim] vim9script: Unexpected type mismatch (#8773)

10 views
Skip to first unread message

Lifepillar

unread,
Aug 19, 2021, 6:20:00 AM8/19/21
to vim/vim, Subscribed

Consider this somewhat contrived code:

vim9script

def Foo(Parser: func(dict<any>): dict<any>): func(dict<any>): dict<any>
  return (ast: dict<any>): dict<any> => {
    return Parser(ast)
  }
enddef

var Expr: func(dict<any>): dict<any>

const Call = Foo(Expr)

When sourced, it results in:

E1013: Argument 1: type mismatch, expected func(dict<any>): dict<any> but got func(): any

I would expect the code to compile, not a typing error.

  • Vim version: 8.2.3350


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

Lifepillar

unread,
Aug 19, 2021, 6:58:27 AM8/19/21
to vim/vim, Subscribed

Maybe I have wrong expectations about the laziness of the evaluation. It seems that the definition of Expr() is bound at the time Foo() is invoked, and not, as I thought, at the time Call() is invoked.

Bram Moolenaar

unread,
Aug 19, 2021, 3:09:10 PM8/19/21
to vim/vim, Subscribed

Closed #8773 via c66f645.

Bram Moolenaar

unread,
Aug 19, 2021, 3:09:42 PM8/19/21
to vim/vim, Subscribed


> Consider this somewhat contrived code:
>
> ```vim

> vim9script
>
> def Foo(Parser: func(dict<any>): dict<any>): func(dict<any>): dict<any>
> return (ast: dict<any>): dict<any> => {
> return Parser(ast)
> }
> enddef
>
> var Expr: func(dict<any>): dict<any>
>
> const Call = Foo(Expr)
> ```
>
> When sourced, it results in:
>
> ```
> E1013: Argument 1: type mismatch, expected func(dict<any>): dict<any> but got func(): any
> ```
>
> I would expect the code to compile, not a typing error.

It does compile, the error happens when calling Foo() with "Expr", which
is not set.

Since the function reference is NULL, it does not have a type. I tried
skipping the type check, but then there is no error. Thus giving an
error for unknown type looks like the best solution.

--
A programmer's wife asks him: "Please run to the store and pick up a loaf of
bread. If they have eggs, get a dozen". The programmer comes home with 12
loafs of bread.

/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

lacygoill

unread,
Aug 19, 2021, 6:44:40 PM8/19/21
to vim/vim, Subscribed

Thus giving an error for unknown type looks like the best solution.

Then why not giving the same error in compiled code?

vim9script
def Foo(Parser: func(dict<any>): dict<any>): func(dict<any>): dict<any>
  return (ast: dict<any>): dict<any> => {
    return Parser(ast)
  }
enddef
var Expr: func(dict<any>): dict<any>
def Func()
    const Call = Foo(Expr)
enddef
Func()

It's the exact same code. The only difference comes from Foo(Expr) which is run from a :def function, instead of being at the script level.

Bram Moolenaar

unread,
Aug 20, 2021, 4:54:42 PM8/20/21
to vim/vim, Subscribed


> > Thus giving an error for unknown type looks like the best solution.
>
> Then why not giving the same error in compiled code?
> ```vim

> vim9script
> def Foo(Parser: func(dict<any>): dict<any>): func(dict<any>): dict<any>
> return (ast: dict<any>): dict<any> => {
> return Parser(ast)
> }
> enddef
> var Expr: func(dict<any>): dict<any>
> def Func()
> const Call = Foo(Expr)
> enddef
> Func()
> ```
> It's the exact same code. The only difference comes from `Foo(Expr)`
> which is run from a `:def` function, instead of being at the script
> level.

It's not exactly the same code, but I can see that it's similar enough
that you wonder why it's handled differently.

What happens in the compiled function is that the type of "Expr" is
looked up from the variable. When compiling the expression the type is
passed around. There is no value when compiling, only when executing
the compiled function.

When calling the function directly, the value of "Expr" is passed, but
the type can only be obtained from the value. And if the value is not
set, the type will be incomplete. We do add the type to a list and dict
value, and a function also has a type. But a "null" value does not
have the type. We only know the basic type, which is in the v_type
field.

I have been wondering if the typval_T could include the type beside the
value. This is quite inefficient though, since typval_T is used
everywhere, and we only need the type in a few places. And the type is
a pointer, which means we need to either make a copy when making a copy
of the typval_T, or use a reference counting mechanism. This adds quite
a bit of overhead.

Since passing a "null" value around is rare, I think it's better to just
accept this small disadvantage.


--
"Software is like sex... it's better when it's free."
-- Linus Torvalds, initiator of the free Linux OS
Makes me wonder what FSF stands for...?


/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Reply all
Reply to author
Forward
0 new messages