diff --git a/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_17.py b/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_17.py index b2a7b7b4dd398..649f88a67211d 100644 --- a/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_17.py +++ b/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_17.py @@ -111,3 +111,7 @@ def bar(x: T) -> T: # OK return x bar(t) + + +def cannot_access_in_default[T](t: T = T): # F821 + pass diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 8e8a5f04f4b46..814f2d9f38fab 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -691,6 +691,14 @@ impl<'a> Visitor<'a> for Checker<'a> { self.semantic(), ); + // The default values of the parameters needs to be evaluated in the enclosing + // scope. + for parameter in &**parameters { + if let Some(expr) = parameter.default() { + self.visit_expr(expr); + } + } + self.semantic.push_scope(ScopeKind::Type); if let Some(type_params) = type_params { @@ -715,9 +723,6 @@ impl<'a> Visitor<'a> for Checker<'a> { } } } - if let Some(expr) = parameter.default() { - self.visit_expr(expr); - } } if let Some(expr) = returns { match annotation { diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_17.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_17.py.snap index bb12cf83ab9a8..ad2011d46ce42 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_17.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_17.py.snap @@ -258,3 +258,10 @@ F821_17.py:103:17: F821 Undefined name `t` | ^ F821 104 | return x | + +F821_17.py:116:40: F821 Undefined name `T` + | +116 | def cannot_access_in_default[T](t: T = T): # F821 + | ^ F821 +117 | pass + |