Skip to content

Commit

Permalink
Use stack
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Apr 28, 2023
1 parent f47a9f3 commit 51f14f3
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 19 deletions.
7 changes: 6 additions & 1 deletion crates/ruff/src/checkers/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions crates/ruff/src/rules/pyflakes/rules/undefined_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 6 additions & 5 deletions crates/ruff_python_semantic/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand Down Expand Up @@ -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<Item = &Scope> {
Expand Down
26 changes: 15 additions & 11 deletions crates/ruff_python_semantic/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use crate::binding::{BindingId, StarImportation};
pub struct Scope<'a> {
pub id: ScopeId,
pub kind: ScopeKind<'a>,
pub parent: Option<ScopeId>,
/// 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
Expand All @@ -27,19 +26,17 @@ impl<'a> Scope<'a> {
Scope {
id: ScopeId::global(),
kind: ScopeKind::Module,
parent: None,
uses_locals: false,
star_imports: Vec::default(),
bindings: FxHashMap::default(),
shadowed_bindings: FxHashMap::default(),
}
}

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(),
Expand Down Expand Up @@ -186,7 +183,7 @@ pub struct Lambda<'a> {

/// The scopes of a program indexed by [`ScopeId`]
#[derive(Debug)]
pub struct Scopes<'a>(Vec<Scope<'a>>);
pub struct Scopes<'a>(Vec<Scope<'a>>, Vec<ScopeId>);

impl<'a> Scopes<'a> {
/// Returns a reference to the global scope
Expand All @@ -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<Item = ScopeId> + '_ {
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<Item = &Scope> + '_ {
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<ScopeId> {
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())
}
}

Expand Down

0 comments on commit 51f14f3

Please sign in to comment.