mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-20 17:19:59 +00:00
Add a dedicated read result for unbound locals (#5083)
## Summary Small follow-up to #4888 to add a dedicated `ResolvedRead` case for unbound locals, mostly for clarity and documentation purposes (no behavior changes). ## Test Plan `cargo test`
This commit is contained in:
parent
aa41ffcfde
commit
1e497162d1
2 changed files with 65 additions and 12 deletions
|
@ -4355,10 +4355,10 @@ impl<'a> Checker<'a> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
match self.semantic_model.resolve_read(id, expr.range()) {
|
match self.semantic_model.resolve_read(id, expr.range()) {
|
||||||
ResolvedRead::Resolved(..) | ResolvedRead::ImplicitGlobal => {
|
ResolvedRead::Resolved(_) | ResolvedRead::ImplicitGlobal => {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
ResolvedRead::StarImport => {
|
ResolvedRead::WildcardImport => {
|
||||||
// F405
|
// F405
|
||||||
if self.enabled(Rule::UndefinedLocalWithImportStarUsage) {
|
if self.enabled(Rule::UndefinedLocalWithImportStarUsage) {
|
||||||
let sources: Vec<String> = self
|
let sources: Vec<String> = self
|
||||||
|
@ -4381,7 +4381,7 @@ impl<'a> Checker<'a> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ResolvedRead::NotFound => {
|
ResolvedRead::NotFound | ResolvedRead::UnboundLocal(_) => {
|
||||||
// F821
|
// F821
|
||||||
if self.enabled(Rule::UndefinedName) {
|
if self.enabled(Rule::UndefinedName) {
|
||||||
// Allow __path__.
|
// Allow __path__.
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub struct SemanticModel<'a> {
|
||||||
|
|
||||||
/// Map from binding ID to binding ID that it shadows (in another scope).
|
/// Map from binding ID to binding ID that it shadows (in another scope).
|
||||||
///
|
///
|
||||||
/// For example:
|
/// For example, given:
|
||||||
/// ```python
|
/// ```python
|
||||||
/// import x
|
/// import x
|
||||||
///
|
///
|
||||||
|
@ -266,6 +266,7 @@ impl<'a> SemanticModel<'a> {
|
||||||
// The `name` in `print(name)` should be treated as unresolved, but the `name` in
|
// The `name` in `print(name)` should be treated as unresolved, but the `name` in
|
||||||
// `name: str` should be treated as used.
|
// `name: str` should be treated as used.
|
||||||
BindingKind::Annotation => continue,
|
BindingKind::Annotation => continue,
|
||||||
|
|
||||||
// If it's a deletion, don't treat it as resolved, since the name is now
|
// If it's a deletion, don't treat it as resolved, since the name is now
|
||||||
// unbound. For example, given:
|
// unbound. For example, given:
|
||||||
//
|
//
|
||||||
|
@ -276,11 +277,15 @@ impl<'a> SemanticModel<'a> {
|
||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
// The `x` in `print(x)` should be treated as unresolved.
|
// The `x` in `print(x)` should be treated as unresolved.
|
||||||
BindingKind::Deletion | BindingKind::UnboundException => break,
|
BindingKind::Deletion | BindingKind::UnboundException => {
|
||||||
_ => {}
|
return ResolvedRead::UnboundLocal(binding_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolvedRead::Resolved(binding_id);
|
// Otherwise, treat it as resolved.
|
||||||
|
_ => {
|
||||||
|
return ResolvedRead::Resolved(binding_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow usages of `__module__` and `__qualname__` within class scopes, e.g.:
|
// Allow usages of `__module__` and `__qualname__` within class scopes, e.g.:
|
||||||
|
@ -309,7 +314,7 @@ impl<'a> SemanticModel<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if import_starred {
|
if import_starred {
|
||||||
ResolvedRead::StarImport
|
ResolvedRead::WildcardImport
|
||||||
} else {
|
} else {
|
||||||
ResolvedRead::NotFound
|
ResolvedRead::NotFound
|
||||||
}
|
}
|
||||||
|
@ -1065,14 +1070,62 @@ pub struct Snapshot {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ResolvedRead {
|
pub enum ResolvedRead {
|
||||||
/// The read reference is resolved to a specific binding.
|
/// The read reference is resolved to a specific binding.
|
||||||
|
///
|
||||||
|
/// For example, given:
|
||||||
|
/// ```python
|
||||||
|
/// x = 1
|
||||||
|
/// print(x)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The `x` in `print(x)` is resolved to the binding of `x` in `x = 1`.
|
||||||
Resolved(BindingId),
|
Resolved(BindingId),
|
||||||
|
|
||||||
/// The read reference is resolved to a context-specific, implicit global (e.g., `__class__`
|
/// The read reference is resolved to a context-specific, implicit global (e.g., `__class__`
|
||||||
/// within a class scope).
|
/// within a class scope).
|
||||||
|
///
|
||||||
|
/// For example, given:
|
||||||
|
/// ```python
|
||||||
|
/// class C:
|
||||||
|
/// print(__class__)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The `__class__` in `print(__class__)` is resolved to the implicit global `__class__`.
|
||||||
ImplicitGlobal,
|
ImplicitGlobal,
|
||||||
/// The read reference is unresolved, but at least one of the containing scopes contains a star
|
|
||||||
/// import.
|
/// The read reference is unresolved, but at least one of the containing scopes contains a
|
||||||
StarImport,
|
/// wildcard import.
|
||||||
|
///
|
||||||
|
/// For example, given:
|
||||||
|
/// ```python
|
||||||
|
/// from x import *
|
||||||
|
///
|
||||||
|
/// print(y)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The `y` in `print(y)` is unresolved, but the containing scope contains a wildcard import,
|
||||||
|
/// so `y` _may_ be resolved to a symbol imported by the wildcard import.
|
||||||
|
WildcardImport,
|
||||||
|
|
||||||
|
/// The read reference is resolved, but to an unbound local variable.
|
||||||
|
///
|
||||||
|
/// For example, given:
|
||||||
|
/// ```python
|
||||||
|
/// x = 1
|
||||||
|
/// del x
|
||||||
|
/// print(x)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The `x` in `print(x)` is an unbound local.
|
||||||
|
UnboundLocal(BindingId),
|
||||||
|
|
||||||
/// The read reference is definitively unresolved.
|
/// The read reference is definitively unresolved.
|
||||||
|
///
|
||||||
|
/// For example, given:
|
||||||
|
/// ```python
|
||||||
|
/// print(x)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The `x` in `print(x)` is definitively unresolved.
|
||||||
NotFound,
|
NotFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue