-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
when in generic should fail earlier #8603
Comments
Actually there is nothing wrong. The For another example, the following is valid: proc sum[A](xs: seq[A]): A =
result = 0
for x in xs:
result += x
echo sum(@[1, 2, 3])
echo sum(@[1.0, 2.0, 3.0]) but if you try to call |
The code is never valid. The identifier |
I am sure it is never valid. But, as I mentioned, the compiler does not try do compile generic procs until they are specialized, it just parses them, because it does not have enough information on the types and symbols in general |
That's correct for the first error message, but not for the second |
In fact I just checked and the compiler does detect errors on missing identifiers - if these identifiers are in non-static code. For instance, the following will not compile: proc sum[A](xs: seq[A]): A =
result = 0
for x in xs:
result += y even if |
Yes, that's what I thought too. In fact when the signature is changed to |
Yeah... this sucks but I'm pretty sure this isn't a bug. |
Er, it's a bug and a rather simple one. The generic pre-pass in |
@zah I tried to come up with a fix for this issue but I haven't gone too far, our definition of "easy" must not be the same 😆 Basically I've come up with the following: devel...drslump:fixes-8603-undeclared-symbols-on-when-statements It now correctly reports as an error the following case: when undef_symbol:
return But that's about it, anything more complex than a simple symbol is not detected. I've tried to follow your advice and traverse the condition expression normally and then the body adding the I would be happy to have another go at it, but I guess it's above my current knowledge level so I will need some guidance to get there. |
Here are new examples related to the problem, I think proc test1(a: string): string = a
when -134: # why does int work here but not `if -134:`?
echo 1
template test2(a: string): int = test1(a) # this triggers no error if not invoced although different return type
# proc test3(a: string): int = test1(a) # but this one is checked correctly!
elif true:
echo 2
else:
this_compiles---------X&Y(A)*A&&&&&&&&A
when array: echo "this compiles"
when "abc": echo "this compiles"
when openArray[int]: echo "this compiles"
when typedesc: echo "this compiles"
# note the different error messages for the following examples:
# if proc: discard
# when proc: discard
#
# both should yield the same error!
# it seems `when` evaluates before checking I think if checking |
when
should check the code at the same depth like if
@Tim-St it's not possible make The bug here is that the guard expressions (the conditions that tell if it should use a block of expression or another) do have to be valid code always. That's explained in the manual actually:
So for example: when this_compiles---------X&Y(A)*A&&&&&&&&A: # should produce an error
...
when false:
this_compiles---------X&Y(A)*A&&&&&&&&A # no error here, since the condition never succeeds Edit: I know it's too late for syntax changes but I also found it surprising the semantics of |
Ok, I understand that the part that cannot be reached is just ignored by the compiler, so you can write there what you want, but something like this should be checked also when it's not invoced? proc test1(a: string): string = a
template test2(a: string): int = test1(a) # this triggers no error if not invoced although different return type
let i: int = test2("a") |
a template is meta programming, think of it as being an abstract form that is ignored in later stages of the compiler unless it's applied. When you call it then the compiler will have the information it needs to generate a concrete type from that abstract form via a specialization or a monophormization process. Basically it replaces the AST nodes of the template call with the expansion of its body, not a real function call at runtime. Now you could argue that the evaluation in Nim is closed over a module, it should detect that The only caveat is now what happens if you export |
The fix I imagine is that you should just call |
Yeah, I tried that, it's probably the good solution but it breaks when processing more complex expressions (on I guess a potential solution would be to modify the |
I'll have to look at some specific examples. Inside the compiler, we keep track of which generic symbols are in "unresolved" state and we need to add guards in the code detecting such symbols in many places. I suspect something similar is going on here as well. |
A particularly egregious example: const x = "qwe"
when x:
echo x
else:
echo "wtf?" Output:
This shouldn't compile. |
Only the behaviour from the original post is still the same. If that's not a problem this can get closed. |
when
should check the code at the same depth like if
Here is an other example code that fails too late (only when used), I think it's related to the same problem: type A* = object
b: var A # wrong here
c: string
# var a: A # only detected when this is uncommented / when `A` is used. |
@Tim-St: That's an unrelated bug that has also been reported. The original code should not compile but does so the bug needs to remain open. |
@Araq Ok, I reopened the linked bug. |
The original code is now correctly detected by the compiler, but this one is not: proc enumToString*(enums: openArray[enum]): string =
mixin enums
when enums.low.ord >= 0 and enums.high.ord < 256:
result = newStringOfCap(enums.len)
else:
result = newStringOfCap(enums.len * 2)
type Test = enum A, B, C
# discard enumToString([A, B, C]) # only detected when uncommented Maybe a bit related to #9567 Update: When you compare the codes (also the original one) in vscode you see that there are two different problems marked red (incorrect). But only one problem is detected: |
There is no deep checking for generics, only a symbol lookup pass. |
The following code compiles on devel (and older) if the proc containing the incorrect code is not called.
Only if the line with the comment is uncommented it shows the error message
If I understood correctly, wrong code should always be detected.
The text was updated successfully, but these errors were encountered: