Improve some behavior around global handling (#1154)

This commit is contained in:
Charlie Marsh 2022-12-08 22:47:19 -05:00 committed by GitHub
parent e33582fb0e
commit 229eab6f42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 27 deletions

View file

@ -236,10 +236,28 @@ where
StmtKind::Global { names } => {
let scope_index = *self.scope_stack.last().expect("No current scope found");
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 usage = Some((scope.id, Range::from_located(stmt)));
for name in names {
// Add a binding to the current scope.
let index = self.bindings.len();
self.bindings.push(Binding {
kind: BindingKind::Global,
@ -250,15 +268,6 @@ where
});
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) {
@ -2948,6 +2957,7 @@ impl<'a> Checker<'a> {
}
fn check_deferred_type_definitions(&mut self) {
self.deferred_type_definitions.reverse();
while let Some((expr, in_annotation, (scopes, parents))) =
self.deferred_type_definitions.pop()
{
@ -2967,6 +2977,7 @@ impl<'a> Checker<'a> {
'b: 'a,
{
let mut stacks = vec![];
self.deferred_string_type_definitions.reverse();
while let Some((range, expression, in_annotation, context)) =
self.deferred_string_type_definitions.pop()
{
@ -2996,6 +3007,7 @@ impl<'a> Checker<'a> {
}
fn check_deferred_functions(&mut self) {
self.deferred_functions.reverse();
while let Some((stmt, (scopes, parents), visibility)) = self.deferred_functions.pop() {
self.scope_stack = scopes.clone();
self.parents = parents.clone();
@ -3041,6 +3053,7 @@ impl<'a> Checker<'a> {
}
fn check_deferred_lambdas(&mut self) {
self.deferred_lambdas.reverse();
while let Some((expr, (scopes, parents))) = self.deferred_lambdas.pop() {
self.scope_stack = scopes.clone();
self.parents = parents.clone();
@ -3063,6 +3076,7 @@ impl<'a> Checker<'a> {
}
fn check_deferred_assignments(&mut self) {
self.deferred_assignments.reverse();
while let Some((index, (scopes, _parents))) = self.deferred_assignments.pop() {
if self.settings.enabled.contains(&CheckCode::F841) {
self.add_checks(
@ -3105,7 +3119,12 @@ impl<'a> Checker<'a> {
}
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
.values
.get("__all__")

View file

@ -392,11 +392,9 @@ mod tests {
Ok(())
}
// TODO(charlie): Bubble global assignments up to the module scope.
#[ignore]
#[test]
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.
flakes(
r#"
@ -405,21 +403,20 @@ mod tests {
"#,
&[],
)?;
flakes(
r#"
def c(): bar
def b(): global bar; bar = 1
"#,
&[],
)?;
// Pyflakes allows this, but it causes other issues.
// flakes(
// r#"
// def c(): bar
// def b(): global bar; bar = 1
// "#,
// &[],
// )?;
Ok(())
}
// TODO(charlie): Bubble global assignments up to the module scope.
#[ignore]
#[test]
fn defined_by_global_multiple_names() -> Result<()> {
// global" can accept multiple names.
// "global" can accept multiple names.
flakes(
r#"
def a(): global fu, bar; fu = 1; bar = 2
@ -1390,9 +1387,9 @@ mod tests {
pass
"#,
&[
CheckCode::F401,
CheckCode::F401,
CheckCode::F811,
CheckCode::F401,
CheckCode::F811,
],
)?;
@ -1981,7 +1978,6 @@ mod tests {
Ok(())
}
#[ignore]
#[test]
fn used_in_global() -> Result<()> {
// A 'global' statement shadowing an unused import should not prevent it
@ -2013,7 +2009,6 @@ mod tests {
Ok(())
}
#[ignore]
#[test]
fn assigned_to_global() -> Result<()> {
// Binding an import to a declared global should not cause it to be