Improve reference resolution for deferred-annotations-within-classes (#4509)

This commit is contained in:
Charlie Marsh
2023-05-19 22:54:18 -04:00
committed by GitHub
parent bb4e674415
commit 9e21414294
8 changed files with 56 additions and 1 deletions

View File

@@ -0,0 +1,10 @@
"""Test: module bindings are preferred over local bindings, for deferred annotations."""
from __future__ import annotations
import datetime
from typing import Optional
class Class:
datetime: Optional[datetime.datetime]

View File

@@ -0,0 +1,12 @@
"""Test: module bindings are preferred over local bindings, for deferred annotations."""
from __future__ import annotations
from typing import TypeAlias, List
class Class:
List: TypeAlias = List
def bar(self) -> List:
pass

View File

@@ -0,0 +1,8 @@
"""Test: module bindings are preferred over local bindings, for deferred annotations."""
import datetime
from typing import Optional
class Class:
datetime: "Optional[datetime.datetime]"

View File

@@ -36,6 +36,9 @@ mod tests {
#[test_case(Rule::UnusedImport, Path::new("F401_9.py"); "F401_9")]
#[test_case(Rule::UnusedImport, Path::new("F401_10.py"); "F401_10")]
#[test_case(Rule::UnusedImport, Path::new("F401_11.py"); "F401_11")]
#[test_case(Rule::UnusedImport, Path::new("F401_12.py"); "F401_12")]
#[test_case(Rule::UnusedImport, Path::new("F401_13.py"); "F401_13")]
#[test_case(Rule::UnusedImport, Path::new("F401_14.py"); "F401_14")]
#[test_case(Rule::ImportShadowedByLoopVar, Path::new("F402.py"); "F402")]
#[test_case(Rule::UndefinedLocalWithImportStar, Path::new("F403.py"); "F403")]
#[test_case(Rule::LateFutureImport, Path::new("F404.py"); "F404")]

View File

@@ -0,0 +1,4 @@
---
source: crates/ruff/src/rules/pyflakes/mod.rs
---

View File

@@ -0,0 +1,4 @@
---
source: crates/ruff/src/rules/pyflakes/mod.rs
---

View File

@@ -0,0 +1,4 @@
---
source: crates/ruff/src/rules/pyflakes/mod.rs
---

View File

@@ -116,6 +116,16 @@ impl<'a> Context<'a> {
/// Resolve a reference to the given symbol.
pub fn resolve_reference(&mut self, symbol: &str, range: TextRange) -> ResolvedReference {
// PEP 563 indicates that if a forward reference can be resolved in the module scope, we
// should prefer it over local resolutions.
if self.in_deferred_type_definition() {
if let Some(binding_id) = self.scopes.global().get(symbol) {
let context = self.execution_context();
self.bindings[*binding_id].mark_used(ScopeId::global(), range, context);
return ResolvedReference::Resolved(ScopeId::global(), *binding_id);
}
}
let mut import_starred = false;
for (index, scope_id) in self.scopes.ancestor_ids(self.scope_id).enumerate() {
let scope = &self.scopes[scope_id];
@@ -750,7 +760,7 @@ impl ContextFlags {
}
/// A snapshot of the [`Context`] at a given point in the AST traversal.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Snapshot {
scope_id: ScopeId,
stmt_id: Option<NodeId>,