diff --git a/crates/ruff/examples/main.rs b/crates/ruff/examples/main.rs index 0043e434a1..9795962968 100644 --- a/crates/ruff/examples/main.rs +++ b/crates/ruff/examples/main.rs @@ -40,8 +40,10 @@ pub struct SubmoduleImportation<'a> { pub full_name: &'a str, } +// If we box, this goes from 48 to 16 +// If we use a u32 pointer, this goes to 8 #[derive(Clone, Debug)] -pub enum BindingKind<'a> { +pub enum BindingKind { Annotation, Argument, Assignment, @@ -54,14 +56,14 @@ pub enum BindingKind<'a> { ClassDefinition, FunctionDefinition, // 32 - Export(Export<'a>), + Export(u32), FutureImportation, // 40 - Importation(Importation<'a>), + Importation(u32), // 48 - FromImportation(FromImportation<'a>), + FromImportation(u32), // 48 - SubmoduleImportation(SubmoduleImportation<'a>), + SubmoduleImportation(u32), } fn main() { diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index 0d9e73574b..44a0163096 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -927,10 +927,9 @@ where self.add_binding( name, Binding { - kind: BindingKind::SubmoduleImportation(SubmoduleImportation { - name, - full_name, - }), + kind: BindingKind::SubmoduleImportation(Box::new( + SubmoduleImportation { name, full_name }, + )), runtime_usage: None, synthetic_usage: None, typing_usage: None, @@ -954,7 +953,10 @@ where self.add_binding( name, Binding { - kind: BindingKind::Importation(Importation { name, full_name }), + kind: BindingKind::Importation(Box::new(Importation { + name, + full_name, + })), runtime_usage: None, synthetic_usage: if is_explicit_reexport { Some((self.ctx.scope_id, alias.range())) @@ -1307,10 +1309,10 @@ where self.add_binding( name, Binding { - kind: BindingKind::FromImportation(FromImportation { + kind: BindingKind::FromImportation(Box::new(FromImportation { name, full_name, - }), + })), runtime_usage: None, synthetic_usage: if is_explicit_reexport { Some((self.ctx.scope_id, alias.range())) @@ -4412,13 +4414,13 @@ impl<'a> Checker<'a> { // import pyarrow.csv // print(pa.csv.read_csv("test.csv")) match &self.ctx.bindings[*index].kind { - BindingKind::Importation(Importation { name, full_name }) - | BindingKind::SubmoduleImportation(SubmoduleImportation { name, full_name }) => - { + BindingKind::Importation(import) => { + let name = import.name; + let full_name = import.full_name; let has_alias = full_name .split('.') .last() - .map(|segment| &segment != name) + .map(|segment| segment != name) .unwrap_or_default(); if has_alias { // Mark the sub-importation as used. @@ -4431,11 +4433,32 @@ impl<'a> Checker<'a> { } } } - BindingKind::FromImportation(FromImportation { name, full_name }) => { + BindingKind::SubmoduleImportation(import) => { + let name = import.name; + let full_name = import.full_name; let has_alias = full_name .split('.') .last() - .map(|segment| &segment != name) + .map(|segment| segment != name) + .unwrap_or_default(); + if has_alias { + // Mark the sub-importation as used. + if let Some(index) = scope.get(full_name) { + self.ctx.bindings[*index].mark_used( + self.ctx.scope_id, + expr.range(), + context, + ); + } + } + } + BindingKind::FromImportation(import) => { + let name = import.name; + let full_name = &import.full_name; + let has_alias = full_name + .split('.') + .last() + .map(|segment| segment != name) .unwrap_or_default(); if has_alias { // Mark the sub-importation as used. @@ -4665,10 +4688,8 @@ impl<'a> Checker<'a> { // Grab the existing bound __all__ values. if let StmtKind::AugAssign { .. } = &parent.node { if let Some(index) = scope.get("__all__") { - if let BindingKind::Export(Export { names: existing }) = - &self.ctx.bindings[*index].kind - { - names.extend_from_slice(existing); + if let BindingKind::Export(export) = &self.ctx.bindings[*index].kind { + names.extend(&export.names); } } } @@ -4693,7 +4714,7 @@ impl<'a> Checker<'a> { self.add_binding( id, Binding { - kind: BindingKind::Export(Export { names: all_names }), + kind: BindingKind::Export(Box::new(Export { names: all_names })), runtime_usage: None, synthetic_usage: None, typing_usage: None, @@ -4981,7 +5002,7 @@ impl<'a> Checker<'a> { .get("__all__") .map(|index| &self.ctx.bindings[*index]) .and_then(|binding| match &binding.kind { - BindingKind::Export(Export { names }) => Some((names, binding.range)), + BindingKind::Export(export) => Some((&export.names, binding.range)), _ => None, }); @@ -5013,7 +5034,7 @@ impl<'a> Checker<'a> { .get("__all__") .map(|index| &self.ctx.bindings[*index]) .and_then(|binding| match &binding.kind { - BindingKind::Export(Export { names }) => Some((names.as_slice(), binding.range)), + BindingKind::Export(export) => Some((export.names.as_slice(), binding.range)), _ => None, }); @@ -5223,14 +5244,9 @@ impl<'a> Checker<'a> { let binding = &self.ctx.bindings[*index]; let full_name = match &binding.kind { - BindingKind::Importation(Importation { full_name, .. }) => full_name, - BindingKind::FromImportation(FromImportation { full_name, .. }) => { - full_name.as_str() - } - BindingKind::SubmoduleImportation(SubmoduleImportation { - full_name, - .. - }) => full_name, + BindingKind::Importation(import) => import.full_name, + BindingKind::FromImportation(import) => import.full_name.as_str(), + BindingKind::SubmoduleImportation(import) => import.full_name, _ => continue, }; diff --git a/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs b/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs index 3349e19aad..4b1f738013 100644 --- a/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs +++ b/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs @@ -51,9 +51,9 @@ impl Violation for RuntimeImportInTypeCheckingBlock { /// TCH004 pub fn runtime_import_in_type_checking_block(binding: &Binding) -> Option { let full_name = match &binding.kind { - BindingKind::Importation(Importation { full_name, .. }) => full_name, - BindingKind::FromImportation(FromImportation { full_name, .. }) => full_name.as_str(), - BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => full_name, + BindingKind::Importation(import) => import.full_name, + BindingKind::FromImportation(import) => import.full_name.as_str(), + BindingKind::SubmoduleImportation(import) => import.full_name, _ => return None, }; diff --git a/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs b/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs index 8af8156563..fc06561589 100644 --- a/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs +++ b/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs @@ -161,66 +161,67 @@ impl Violation for TypingOnlyStandardLibraryImport { /// Return `true` if `this` is implicitly loaded via importing `that`. fn is_implicit_import(this: &Binding, that: &Binding) -> bool { - match &this.kind { - BindingKind::Importation(Importation { - full_name: this_name, - .. - }) - | BindingKind::SubmoduleImportation(SubmoduleImportation { - name: this_name, .. - }) => match &that.kind { - BindingKind::FromImportation(FromImportation { - full_name: that_name, - .. - }) => { - // Ex) `pkg.A` vs. `pkg` - this_name - .rfind('.') - .map_or(false, |i| this_name[..i] == *that_name) - } - BindingKind::Importation(Importation { - full_name: that_name, - .. - }) - | BindingKind::SubmoduleImportation(SubmoduleImportation { - name: that_name, .. - }) => { - // Ex) `pkg.A` vs. `pkg.B` - this_name == that_name - } - _ => false, - }, - BindingKind::FromImportation(FromImportation { - full_name: this_name, - .. - }) => match &that.kind { - BindingKind::Importation(Importation { - full_name: that_name, - .. - }) - | BindingKind::SubmoduleImportation(SubmoduleImportation { - name: that_name, .. - }) => { - // Ex) `pkg.A` vs. `pkg` - this_name - .rfind('.') - .map_or(false, |i| &this_name[..i] == *that_name) - } - BindingKind::FromImportation(FromImportation { - full_name: that_name, - .. - }) => { - // Ex) `pkg.A` vs. `pkg.B` - this_name.rfind('.').map_or(false, |i| { - that_name - .rfind('.') - .map_or(false, |j| this_name[..i] == that_name[..j]) - }) - } - _ => false, - }, - _ => false, - } + true + // match &this.kind { + // BindingKind::Importation(Importation { + // full_name: this_name, + // .. + // }) + // | BindingKind::SubmoduleImportation(SubmoduleImportation { + // name: this_name, .. + // }) => match &that.kind { + // BindingKind::FromImportation(FromImportation { + // full_name: that_name, + // .. + // }) => { + // // Ex) `pkg.A` vs. `pkg` + // this_name + // .rfind('.') + // .map_or(false, |i| this_name[..i] == *that_name) + // } + // BindingKind::Importation(Importation { + // full_name: that_name, + // .. + // }) + // | BindingKind::SubmoduleImportation(SubmoduleImportation { + // name: that_name, .. + // }) => { + // // Ex) `pkg.A` vs. `pkg.B` + // this_name == that_name + // } + // _ => false, + // }, + // BindingKind::FromImportation(FromImportation { + // full_name: this_name, + // .. + // }) => match &that.kind { + // BindingKind::Importation(Importation { + // full_name: that_name, + // .. + // }) + // | BindingKind::SubmoduleImportation(SubmoduleImportation { + // name: that_name, .. + // }) => { + // // Ex) `pkg.A` vs. `pkg` + // this_name + // .rfind('.') + // .map_or(false, |i| &this_name[..i] == *that_name) + // } + // BindingKind::FromImportation(FromImportation { + // full_name: that_name, + // .. + // }) => { + // // Ex) `pkg.A` vs. `pkg.B` + // this_name.rfind('.').map_or(false, |i| { + // that_name + // .rfind('.') + // .map_or(false, |j| this_name[..i] == that_name[..j]) + // }) + // } + // _ => false, + // }, + // _ => false, + // } } /// Return `true` if `name` is exempt from typing-only enforcement. @@ -257,9 +258,9 @@ pub fn typing_only_runtime_import( } let full_name = match &binding.kind { - BindingKind::Importation(Importation { full_name, .. }) => full_name, - BindingKind::FromImportation(FromImportation { full_name, .. }) => full_name.as_str(), - BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => full_name, + BindingKind::Importation(import) => import.full_name, + BindingKind::FromImportation(import) => import.full_name.as_str(), + BindingKind::SubmoduleImportation(import) => import.full_name, _ => return None, }; diff --git a/crates/ruff/src/rules/pandas_vet/rules/check_call.rs b/crates/ruff/src/rules/pandas_vet/rules/check_call.rs index 494e33909e..b9c3839dd9 100644 --- a/crates/ruff/src/rules/pandas_vet/rules/check_call.rs +++ b/crates/ruff/src/rules/pandas_vet/rules/check_call.rs @@ -85,11 +85,8 @@ pub fn check_call(checker: &mut Checker, func: &Expr) { // irrelevant bindings (like non-Pandas imports). if let ExprKind::Name { id, .. } = &value.node { if checker.ctx.find_binding(id).map_or(true, |binding| { - if let BindingKind::Importation(Importation { - full_name: module, .. - }) = &binding.kind - { - module != &"pandas" + if let BindingKind::Importation(import) = &binding.kind { + import.full_name != "pandas" } else { matches!( binding.kind, diff --git a/crates/ruff_python_semantic/src/binding.rs b/crates/ruff_python_semantic/src/binding.rs index fe0d2ceadd..d12756b9e3 100644 --- a/crates/ruff_python_semantic/src/binding.rs +++ b/crates/ruff_python_semantic/src/binding.rs @@ -59,45 +59,28 @@ impl<'a> Binding<'a> { pub fn redefines(&self, existing: &'a Binding) -> bool { match &self.kind { - BindingKind::Importation(Importation { full_name, .. }) => { - if let BindingKind::SubmoduleImportation(SubmoduleImportation { - full_name: existing, - .. - }) = &existing.kind - { - return full_name == existing; + BindingKind::Importation(import) => { + if let BindingKind::SubmoduleImportation(existing) = &existing.kind { + return import.full_name == existing.full_name; } } - BindingKind::FromImportation(FromImportation { full_name, .. }) => { - if let BindingKind::SubmoduleImportation(SubmoduleImportation { - full_name: existing, - .. - }) = &existing.kind - { - return full_name == existing; + BindingKind::FromImportation(import) => { + if let BindingKind::SubmoduleImportation(existing) = &existing.kind { + return import.full_name == existing.full_name; } } - BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => { - match &existing.kind { - BindingKind::Importation(Importation { - full_name: existing, - .. - }) - | BindingKind::SubmoduleImportation(SubmoduleImportation { - full_name: existing, - .. - }) => { - return full_name == existing; - } - BindingKind::FromImportation(FromImportation { - full_name: existing, - .. - }) => { - return full_name == existing; - } - _ => {} + BindingKind::SubmoduleImportation(import) => match &existing.kind { + BindingKind::Importation(existing) => { + return import.full_name == existing.full_name; } - } + BindingKind::SubmoduleImportation(existing) => { + return import.full_name == existing.full_name; + } + BindingKind::FromImportation(existing) => { + return import.full_name == existing.full_name; + } + _ => {} + }, BindingKind::Annotation => { return false; } @@ -259,11 +242,11 @@ pub enum BindingKind<'a> { Builtin, ClassDefinition, FunctionDefinition, - Export(Export<'a>), + Export(Box>), FutureImportation, - Importation(Importation<'a>), - FromImportation(FromImportation<'a>), - SubmoduleImportation(SubmoduleImportation<'a>), + Importation(Box>), + FromImportation(Box>), + SubmoduleImportation(Box>), } bitflags! { diff --git a/crates/ruff_python_semantic/src/context.rs b/crates/ruff_python_semantic/src/context.rs index 29bc3a4fe5..34e5915ada 100644 --- a/crates/ruff_python_semantic/src/context.rs +++ b/crates/ruff_python_semantic/src/context.rs @@ -166,10 +166,8 @@ impl<'a> Context<'a> { return None; }; match &binding.kind { - BindingKind::Importation(Importation { - full_name: name, .. - }) - | BindingKind::SubmoduleImportation(SubmoduleImportation { name, .. }) => { + BindingKind::Importation(import) => { + let name = import.full_name; if name.starts_with('.') { if let Some(module) = &self.module_path { let mut source_path = from_relative_import(module, name); @@ -188,9 +186,28 @@ impl<'a> Context<'a> { Some(source_path) } } - BindingKind::FromImportation(FromImportation { - full_name: name, .. - }) => { + BindingKind::SubmoduleImportation(import) => { + let name = import.name; + if name.starts_with('.') { + if let Some(module) = &self.module_path { + let mut source_path = from_relative_import(module, name); + if source_path.is_empty() { + None + } else { + source_path.extend(call_path.into_iter().skip(1)); + Some(source_path) + } + } else { + None + } + } else { + let mut source_path: CallPath = from_unqualified_name(name); + source_path.extend(call_path.into_iter().skip(1)); + Some(source_path) + } + } + BindingKind::FromImportation(import) => { + let name = &import.full_name; if name.starts_with('.') { if let Some(module) = &self.module_path { let mut source_path = from_relative_import(module, name); @@ -243,16 +260,19 @@ impl<'a> Context<'a> { // Ex) Given `module="sys"` and `object="exit"`: // `import sys` -> `sys.exit` // `import sys as sys2` -> `sys2.exit` - BindingKind::Importation(Importation { name, full_name }) => { - if full_name == &module { + BindingKind::Importation(import) => { + if import.full_name == module { // Verify that `sys` isn't bound in an inner scope. if self .scopes() .take(scope_index) - .all(|scope| scope.get(name).is_none()) + .all(|scope| scope.get(import.name).is_none()) { if let Some(source) = binding.source { - return Some((self.stmts[source], format!("{name}.{member}"))); + return Some(( + self.stmts[source], + format!("{}.{member}", import.name), + )); } } } @@ -260,17 +280,22 @@ impl<'a> Context<'a> { // Ex) Given `module="os.path"` and `object="join"`: // `from os.path import join` -> `join` // `from os.path import join as join2` -> `join2` - BindingKind::FromImportation(FromImportation { name, full_name }) => { - if let Some((target_module, target_member)) = full_name.split_once('.') { + BindingKind::FromImportation(import) => { + if let Some((target_module, target_member)) = + import.full_name.split_once('.') + { if target_module == module && target_member == member { // Verify that `join` isn't bound in an inner scope. if self .scopes() .take(scope_index) - .all(|scope| scope.get(name).is_none()) + .all(|scope| scope.get(import.name).is_none()) { if let Some(source) = binding.source { - return Some((self.stmts[source], (*name).to_string())); + return Some(( + self.stmts[source], + (*import.name).to_string(), + )); } } } @@ -278,16 +303,19 @@ impl<'a> Context<'a> { } // Ex) Given `module="os"` and `object="name"`: // `import os.path ` -> `os.name` - BindingKind::SubmoduleImportation(SubmoduleImportation { name, .. }) => { - if name == &module { + BindingKind::SubmoduleImportation(import) => { + if import.name == module { // Verify that `os` isn't bound in an inner scope. if self .scopes() .take(scope_index) - .all(|scope| scope.get(name).is_none()) + .all(|scope| scope.get(import.name).is_none()) { if let Some(source) = binding.source { - return Some((self.stmts[source], format!("{name}.{member}"))); + return Some(( + self.stmts[source], + format!("{}.{member}", import.name), + )); } } }