From 51f14f35382eadab3d91fe66d0b5b966ca9a2350 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 28 Apr 2023 12:50:17 -0400 Subject: [PATCH] Use stack --- crates/ruff/src/checkers/ast/mod.rs | 7 ++++- .../rules/pyflakes/rules/undefined_local.rs | 4 +-- crates/ruff_python_semantic/src/context.rs | 11 ++++---- crates/ruff_python_semantic/src/scope.rs | 26 +++++++++++-------- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index 08aa0ab21094cc..de008fb564bf2c 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -4861,7 +4861,12 @@ impl<'a> Checker<'a> { Rule::UnusedLambdaArgument, ]) { let scope = &self.ctx.scopes[scope_id]; - let parent = &self.ctx.scopes[scope.parent.unwrap()]; + let parent = &self + .ctx + .scopes + .parent(scope_id) + .map(|scope_id| &self.ctx.scopes[scope_id]) + .unwrap(); self.diagnostics .extend(flake8_unused_arguments::rules::unused_arguments( self, diff --git a/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs b/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs index e403ab123905aa..5277ea45aec5c4 100644 --- a/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs +++ b/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs @@ -27,12 +27,12 @@ pub fn undefined_local(checker: &mut Checker, name: &str) { return; } - let Some(parent) = current.parent else { + let Some(parent_scope_id) = checker.ctx.scopes.parent(current.id) else { return; }; // For every function and module scope above us... - for scope_id in checker.ctx.scopes.ancestors(parent) { + for scope_id in checker.ctx.scopes.ancestors(parent_scope_id) { let scope = &checker.ctx.scopes[scope_id]; if !(scope.kind.is_function() || scope.kind.is_module()) { continue; diff --git a/crates/ruff_python_semantic/src/context.rs b/crates/ruff_python_semantic/src/context.rs index d9d747fe4dad9c..da30c86c02c710 100644 --- a/crates/ruff_python_semantic/src/context.rs +++ b/crates/ruff_python_semantic/src/context.rs @@ -339,8 +339,9 @@ impl<'a> Context<'a> { /// Pop the current [`Scope`] off the stack. pub fn pop_scope(&mut self) { self.dead_scopes.push(self.scope_id); - self.scope_id = self.scopes[self.scope_id] - .parent + self.scope_id = self + .scopes + .parent(self.scope_id) .expect("Attempted to pop without scope"); } @@ -400,9 +401,9 @@ impl<'a> Context<'a> { } pub fn parent_scope(&self) -> Option<&Scope> { - self.scopes[self.scope_id] - .parent - .map(|index| &self.scopes[index]) + self.scopes + .parent(self.scope_id) + .map(|scope_id| &self.scopes[scope_id]) } pub fn scopes(&self) -> impl Iterator { diff --git a/crates/ruff_python_semantic/src/scope.rs b/crates/ruff_python_semantic/src/scope.rs index ca8c64b4f492db..cdc08ca47ae535 100644 --- a/crates/ruff_python_semantic/src/scope.rs +++ b/crates/ruff_python_semantic/src/scope.rs @@ -10,7 +10,6 @@ use crate::binding::{BindingId, StarImportation}; pub struct Scope<'a> { pub id: ScopeId, pub kind: ScopeKind<'a>, - pub parent: Option, /// Whether this scope uses the `locals()` builtin. pub uses_locals: bool, /// A list of star imports in this scope. These represent _module_ imports (e.g., `sys` in @@ -27,7 +26,6 @@ impl<'a> Scope<'a> { Scope { id: ScopeId::global(), kind: ScopeKind::Module, - parent: None, uses_locals: false, star_imports: Vec::default(), bindings: FxHashMap::default(), @@ -35,11 +33,10 @@ impl<'a> Scope<'a> { } } - pub fn local(id: ScopeId, parent: ScopeId, kind: ScopeKind<'a>) -> Self { + pub fn local(id: ScopeId, kind: ScopeKind<'a>) -> Self { Scope { id, kind, - parent: Some(parent), uses_locals: false, star_imports: Vec::default(), bindings: FxHashMap::default(), @@ -186,7 +183,7 @@ pub struct Lambda<'a> { /// The scopes of a program indexed by [`ScopeId`] #[derive(Debug)] -pub struct Scopes<'a>(Vec>); +pub struct Scopes<'a>(Vec>, Vec); impl<'a> Scopes<'a> { /// Returns a reference to the global scope @@ -202,26 +199,33 @@ impl<'a> Scopes<'a> { /// Pushes a new scope and returns its unique id pub fn push_scope(&mut self, parent: ScopeId, kind: ScopeKind<'a>) -> ScopeId { let next_id = ScopeId::try_from(self.0.len()).unwrap(); - self.0.push(Scope::local(next_id, parent, kind)); + self.0.push(Scope::local(next_id, kind)); + self.1.push(parent); next_id } /// Returns an iterator over all [`ScopeId`] ancestors, starting from the given [`ScopeId`]. pub fn ancestors(&self, scope: ScopeId) -> impl Iterator + '_ { - std::iter::successors(Some(scope), |&scope| self[scope].parent) + std::iter::successors(Some(scope), |&scope| self.parent(scope)) } /// Returns an iterator over all [`Scope`] ancestors, starting from the given [`ScopeId`]. pub fn ancestor_scopes(&self, scope: ScopeId) -> impl Iterator + '_ { - std::iter::successors(Some(&self[scope]), |&scope| { - scope.parent.map(|parent| &self[parent]) - }) + self.ancestors(scope).map(move |scope| &self[scope]) + } + + pub fn parent(&self, scope: ScopeId) -> Option { + if scope.is_global() { + None + } else { + Some(self.1[usize::from(scope) - 1]) + } } } impl Default for Scopes<'_> { fn default() -> Self { - Self(vec![Scope::global()]) + Self(vec![Scope::global()], Vec::new()) } }