mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 22:54:42 +00:00
Improve some behavior around global handling (#1154)
This commit is contained in:
parent
e33582fb0e
commit
229eab6f42
2 changed files with 41 additions and 27 deletions
|
@ -236,10 +236,28 @@ where
|
||||||
StmtKind::Global { names } => {
|
StmtKind::Global { names } => {
|
||||||
let scope_index = *self.scope_stack.last().expect("No current scope found");
|
let scope_index = *self.scope_stack.last().expect("No current scope found");
|
||||||
if scope_index != GLOBAL_SCOPE_INDEX {
|
if scope_index != GLOBAL_SCOPE_INDEX {
|
||||||
|
// If the binding doesn't already exist in the global scope, add it.
|
||||||
|
for name in names {
|
||||||
|
if !self.scopes[GLOBAL_SCOPE_INDEX]
|
||||||
|
.values
|
||||||
|
.contains_key(&name.as_str())
|
||||||
|
{
|
||||||
|
let index = self.bindings.len();
|
||||||
|
self.bindings.push(Binding {
|
||||||
|
kind: BindingKind::Assignment,
|
||||||
|
used: None,
|
||||||
|
range: Range::from_located(stmt),
|
||||||
|
source: None,
|
||||||
|
redefined: vec![],
|
||||||
|
});
|
||||||
|
self.scopes[GLOBAL_SCOPE_INDEX].values.insert(name, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the binding to the current scope.
|
||||||
let scope = &mut self.scopes[scope_index];
|
let scope = &mut self.scopes[scope_index];
|
||||||
let usage = Some((scope.id, Range::from_located(stmt)));
|
let usage = Some((scope.id, Range::from_located(stmt)));
|
||||||
for name in names {
|
for name in names {
|
||||||
// Add a binding to the current scope.
|
|
||||||
let index = self.bindings.len();
|
let index = self.bindings.len();
|
||||||
self.bindings.push(Binding {
|
self.bindings.push(Binding {
|
||||||
kind: BindingKind::Global,
|
kind: BindingKind::Global,
|
||||||
|
@ -250,15 +268,6 @@ where
|
||||||
});
|
});
|
||||||
scope.values.insert(name, index);
|
scope.values.insert(name, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the binding in the global scope as used.
|
|
||||||
for name in names {
|
|
||||||
if let Some(index) =
|
|
||||||
self.scopes[GLOBAL_SCOPE_INDEX].values.get(&name.as_str())
|
|
||||||
{
|
|
||||||
self.bindings[*index].used = usage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.settings.enabled.contains(&CheckCode::E741) {
|
if self.settings.enabled.contains(&CheckCode::E741) {
|
||||||
|
@ -2948,6 +2957,7 @@ impl<'a> Checker<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_deferred_type_definitions(&mut self) {
|
fn check_deferred_type_definitions(&mut self) {
|
||||||
|
self.deferred_type_definitions.reverse();
|
||||||
while let Some((expr, in_annotation, (scopes, parents))) =
|
while let Some((expr, in_annotation, (scopes, parents))) =
|
||||||
self.deferred_type_definitions.pop()
|
self.deferred_type_definitions.pop()
|
||||||
{
|
{
|
||||||
|
@ -2967,6 +2977,7 @@ impl<'a> Checker<'a> {
|
||||||
'b: 'a,
|
'b: 'a,
|
||||||
{
|
{
|
||||||
let mut stacks = vec![];
|
let mut stacks = vec![];
|
||||||
|
self.deferred_string_type_definitions.reverse();
|
||||||
while let Some((range, expression, in_annotation, context)) =
|
while let Some((range, expression, in_annotation, context)) =
|
||||||
self.deferred_string_type_definitions.pop()
|
self.deferred_string_type_definitions.pop()
|
||||||
{
|
{
|
||||||
|
@ -2996,6 +3007,7 @@ impl<'a> Checker<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_deferred_functions(&mut self) {
|
fn check_deferred_functions(&mut self) {
|
||||||
|
self.deferred_functions.reverse();
|
||||||
while let Some((stmt, (scopes, parents), visibility)) = self.deferred_functions.pop() {
|
while let Some((stmt, (scopes, parents), visibility)) = self.deferred_functions.pop() {
|
||||||
self.scope_stack = scopes.clone();
|
self.scope_stack = scopes.clone();
|
||||||
self.parents = parents.clone();
|
self.parents = parents.clone();
|
||||||
|
@ -3041,6 +3053,7 @@ impl<'a> Checker<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_deferred_lambdas(&mut self) {
|
fn check_deferred_lambdas(&mut self) {
|
||||||
|
self.deferred_lambdas.reverse();
|
||||||
while let Some((expr, (scopes, parents))) = self.deferred_lambdas.pop() {
|
while let Some((expr, (scopes, parents))) = self.deferred_lambdas.pop() {
|
||||||
self.scope_stack = scopes.clone();
|
self.scope_stack = scopes.clone();
|
||||||
self.parents = parents.clone();
|
self.parents = parents.clone();
|
||||||
|
@ -3063,6 +3076,7 @@ impl<'a> Checker<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_deferred_assignments(&mut self) {
|
fn check_deferred_assignments(&mut self) {
|
||||||
|
self.deferred_assignments.reverse();
|
||||||
while let Some((index, (scopes, _parents))) = self.deferred_assignments.pop() {
|
while let Some((index, (scopes, _parents))) = self.deferred_assignments.pop() {
|
||||||
if self.settings.enabled.contains(&CheckCode::F841) {
|
if self.settings.enabled.contains(&CheckCode::F841) {
|
||||||
self.add_checks(
|
self.add_checks(
|
||||||
|
@ -3105,7 +3119,12 @@ impl<'a> Checker<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut checks: Vec<Check> = vec![];
|
let mut checks: Vec<Check> = vec![];
|
||||||
for scope in self.dead_scopes.iter().map(|index| &self.scopes[*index]) {
|
for scope in self
|
||||||
|
.dead_scopes
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.map(|index| &self.scopes[*index])
|
||||||
|
{
|
||||||
let all_binding: Option<&Binding> = scope
|
let all_binding: Option<&Binding> = scope
|
||||||
.values
|
.values
|
||||||
.get("__all__")
|
.get("__all__")
|
||||||
|
|
|
@ -392,11 +392,9 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(charlie): Bubble global assignments up to the module scope.
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn defined_by_global() -> Result<()> {
|
fn defined_by_global() -> Result<()> {
|
||||||
// global" can make an otherwise undefined name in another function
|
// "global" can make an otherwise undefined name in another function
|
||||||
// defined.
|
// defined.
|
||||||
flakes(
|
flakes(
|
||||||
r#"
|
r#"
|
||||||
|
@ -405,21 +403,20 @@ mod tests {
|
||||||
"#,
|
"#,
|
||||||
&[],
|
&[],
|
||||||
)?;
|
)?;
|
||||||
flakes(
|
// Pyflakes allows this, but it causes other issues.
|
||||||
r#"
|
// flakes(
|
||||||
def c(): bar
|
// r#"
|
||||||
def b(): global bar; bar = 1
|
// def c(): bar
|
||||||
"#,
|
// def b(): global bar; bar = 1
|
||||||
&[],
|
// "#,
|
||||||
)?;
|
// &[],
|
||||||
|
// )?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(charlie): Bubble global assignments up to the module scope.
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn defined_by_global_multiple_names() -> Result<()> {
|
fn defined_by_global_multiple_names() -> Result<()> {
|
||||||
// global" can accept multiple names.
|
// "global" can accept multiple names.
|
||||||
flakes(
|
flakes(
|
||||||
r#"
|
r#"
|
||||||
def a(): global fu, bar; fu = 1; bar = 2
|
def a(): global fu, bar; fu = 1; bar = 2
|
||||||
|
@ -1390,9 +1387,9 @@ mod tests {
|
||||||
pass
|
pass
|
||||||
"#,
|
"#,
|
||||||
&[
|
&[
|
||||||
CheckCode::F401,
|
|
||||||
CheckCode::F401,
|
CheckCode::F401,
|
||||||
CheckCode::F811,
|
CheckCode::F811,
|
||||||
|
CheckCode::F401,
|
||||||
CheckCode::F811,
|
CheckCode::F811,
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
@ -1981,7 +1978,6 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn used_in_global() -> Result<()> {
|
fn used_in_global() -> Result<()> {
|
||||||
// A 'global' statement shadowing an unused import should not prevent it
|
// A 'global' statement shadowing an unused import should not prevent it
|
||||||
|
@ -2013,7 +2009,6 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assigned_to_global() -> Result<()> {
|
fn assigned_to_global() -> Result<()> {
|
||||||
// Binding an import to a declared global should not cause it to be
|
// Binding an import to a declared global should not cause it to be
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue