Skip to content

Commit

Permalink
Improve reference resolution for deferred-annotations-within-classes (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh authored May 20, 2023
1 parent bb4e674 commit 9e21414
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 1 deletion.
10 changes: 10 additions & 0 deletions crates/ruff/resources/test/fixtures/pyflakes/F401_12.py
Original file line number Diff line number Diff line change
@@ -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]
12 changes: 12 additions & 0 deletions crates/ruff/resources/test/fixtures/pyflakes/F401_13.py
Original file line number Diff line number Diff line change
@@ -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
8 changes: 8 additions & 0 deletions crates/ruff/resources/test/fixtures/pyflakes/F401_14.py
Original file line number Diff line number Diff line change
@@ -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]"
3 changes: 3 additions & 0 deletions crates/ruff/src/rules/pyflakes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
source: crates/ruff/src/rules/pyflakes/mod.rs
---

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
source: crates/ruff/src/rules/pyflakes/mod.rs
---

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
source: crates/ruff/src/rules/pyflakes/mod.rs
---

12 changes: 11 additions & 1 deletion crates/ruff_python_semantic/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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>,
Expand Down

0 comments on commit 9e21414

Please sign in to comment.