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 committed May 18, 2023
1 parent 728c881 commit cfec627
Show file tree
Hide file tree
Showing 8 changed files with 57 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
---

13 changes: 12 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,17 @@ 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() {
let scope_id = ScopeId::global();
if let Some(binding_id) = self.scopes[scope_id].get(symbol) {
let context = self.execution_context();
self.bindings[*binding_id].mark_used(scope_id, range, context);
return ResolvedReference::Resolved(scope_id, *binding_id);
}
}

let mut first_iter = true;
let mut import_starred = false;
for scope_id in self.scopes.ancestor_ids(self.scope_id) {
Expand Down Expand Up @@ -751,7 +762,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 cfec627

Please sign in to comment.