Evaluate default parameter value in enclosing scope (#12852)
## Summary
This PR fixes a bug in the semantic model where it would evaluate the
default parameter value in the type parameter scope. For example,
```py
def foo[T1: int](a = T1):
pass
```
Here, the `T1` in `a = T1` is undefined but Ruff doesn't flag it
(https://play.ruff.rs/ba2f7c2f-4da6-417e-aa2a-104aa63e6d5e).
The fix here is to evaluate the default parameter value in the
_enclosing_ scope instead.
## Test Plan
Add a test case which includes the above code under `F821`
(`undefined-name`) and validate the snapshot.
This commit is contained in:
@@ -111,3 +111,7 @@ def can_access_inside_nested[T](t: T) -> T: # OK
|
||||
return x
|
||||
|
||||
bar(t)
|
||||
|
||||
|
||||
def cannot_access_in_default[T](t: T = T): # F821
|
||||
pass
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
Reference in New Issue
Block a user