Has someone ever noticed this?
var a = (proc() = discard)
var b: proc() = (proc() = discard)
echo a is proc() {.nimcall.} #true
echo a is proc() {.closure.} #false
# => `a` is {.nimcall.}
echo b is proc() {.nimcall.} #false
echo b is proc() {.closure.} #true
# => `b` is {.closure.}
Although it looks a little weird, it's the correct behavior. I'll explain it later.
From the language manual, we can see that there're three rules affecting the inference of procedural types:
Now let's see the definition of a.
var a = (proc() = discard)
The initializer is a lambda, but not definied in another proc, so it's subject to rule 1; it's {.nimcall.}. According to the manual, if the type is omitted, the variable is of the same type as the initializer. In this case, it is proc() {.nimcall.}.
Now see the definition of b.
var b: proc() = (proc() = discard)
As in the case of a, the initializer is subject to rule 1, so it's {.nimcall.}. However, a type is given. As proc() is a procedural type, it's subject to rule 3, so it's {.closure.}. The manual doesn't exactly say whether a proc() {.nimcall.} can be passed to a proc() {.closure.} as initializer, but it has stated that {.nimcall.} can be passed to a parameter which expects a {.closure.}, so we can infer that it can take the initializer, as a variable-initialization can be considered a call to `=` or =sink, and there was no compile-time error. Therefore, even if initalized with a proc() {.nimcall.}, b is still a {.closure.}
I posted this because I don't want anyone to get into the trap, and I think it should be added to the documentation.