-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
[red-knot] Use Unknown
rather than Unbound
for unresolved imports
#12932
Conversation
|
Makes sense to me but I rather have carl review it ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think this is correct, thanks for the fix!
The awkwardness is that it makes the "unresolved imports" lint rule slightly less clearly correct, because is it now possible that type Unknown on an import doesn't mean unresolved import, but rather successful import of a value of type Unknown in the module we imported from? One way to clarify this would be to clarify our use of Unknown to say that it always originates from a type error (never from just lack-of-annotation), which is currently true. In this case we could reasonably say that Unknown type on an import always means the import failed to resolve. In any case I don't think this is a critical issue for this PR, since we're focusing on building a type checker right now, not a type-aware linter. So as long as we issue the right diagnostic at the moment of failing to resolve an import, it's not currently critical that we can later revisit and draw the same conclusion just from the type. If it later becomes critical, it may be an option to literally look at the presence or absence of the diagnostic, or in some other way store more metadata.
Relatedly, I think if we want to be consistent about this, then in infer_import_from_definition
, where we call .member
on the module type, we should call .replace_unbound_with(Type::Unknown)
on the resulting type. Because importing an unbound name from an actually-existing module is also just another kind of unresolved import, and should also result in Type::Unknown
(not Type::Unbound
) in the importing module. I think it would make sense to add that (and a test for it) in this PR; what do you think?
Yup. And I assume this is the reason why the number of diagnostics in the benchmark is going up slightly? I want to check before merging.
Yeah... I think I've mentioned to you before that mypy tracks quite a few different subkinds of
Yes, that makes sense to me! |
So on
And with this PR the diagnostics are:
So, as expected, this PR means that the "unresolved import" lint becomes less accurate: existing symbols imported from other modules that are
( This looks okay to me (we'll just need to add more metadata in the future to track exactly what the cause of the |
1ccb31f
to
c548278
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thank you!!
Summary
If an import statement succeeds, it always binds a symbol. Symbols introduced by import statements can always be used successfully by other statements and expressions; you'll never get a
NameError
from trying to use a symbol introduced by an import statement. As such, it doesn't make sense to think of unresolved imports as "unbound": an unbound symbol causes a runtimeNameError
when you try to use it elsewhere, but here the runtime error (providing our type analysis is correct) will occur at the import statement itself, not when the symbol introduced by the runtime statement is used elsewhere.This PR therefore updates red-knot to infer
Unknown
rather thanUnbound
in these cases.Test Plan
cargo test