Try boxing

This commit is contained in:
Charlie Marsh 2023-05-06 23:39:06 -04:00
parent cd5c69b61c
commit da8481c97d
7 changed files with 188 additions and 161 deletions

View File

@ -40,8 +40,10 @@ pub struct SubmoduleImportation<'a> {
pub full_name: &'a str, 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)] #[derive(Clone, Debug)]
pub enum BindingKind<'a> { pub enum BindingKind {
Annotation, Annotation,
Argument, Argument,
Assignment, Assignment,
@ -54,14 +56,14 @@ pub enum BindingKind<'a> {
ClassDefinition, ClassDefinition,
FunctionDefinition, FunctionDefinition,
// 32 // 32
Export(Export<'a>), Export(u32),
FutureImportation, FutureImportation,
// 40 // 40
Importation(Importation<'a>), Importation(u32),
// 48 // 48
FromImportation(FromImportation<'a>), FromImportation(u32),
// 48 // 48
SubmoduleImportation(SubmoduleImportation<'a>), SubmoduleImportation(u32),
} }
fn main() { fn main() {

View File

@ -927,10 +927,9 @@ where
self.add_binding( self.add_binding(
name, name,
Binding { Binding {
kind: BindingKind::SubmoduleImportation(SubmoduleImportation { kind: BindingKind::SubmoduleImportation(Box::new(
name, SubmoduleImportation { name, full_name },
full_name, )),
}),
runtime_usage: None, runtime_usage: None,
synthetic_usage: None, synthetic_usage: None,
typing_usage: None, typing_usage: None,
@ -954,7 +953,10 @@ where
self.add_binding( self.add_binding(
name, name,
Binding { Binding {
kind: BindingKind::Importation(Importation { name, full_name }), kind: BindingKind::Importation(Box::new(Importation {
name,
full_name,
})),
runtime_usage: None, runtime_usage: None,
synthetic_usage: if is_explicit_reexport { synthetic_usage: if is_explicit_reexport {
Some((self.ctx.scope_id, alias.range())) Some((self.ctx.scope_id, alias.range()))
@ -1307,10 +1309,10 @@ where
self.add_binding( self.add_binding(
name, name,
Binding { Binding {
kind: BindingKind::FromImportation(FromImportation { kind: BindingKind::FromImportation(Box::new(FromImportation {
name, name,
full_name, full_name,
}), })),
runtime_usage: None, runtime_usage: None,
synthetic_usage: if is_explicit_reexport { synthetic_usage: if is_explicit_reexport {
Some((self.ctx.scope_id, alias.range())) Some((self.ctx.scope_id, alias.range()))
@ -4412,13 +4414,13 @@ impl<'a> Checker<'a> {
// import pyarrow.csv // import pyarrow.csv
// print(pa.csv.read_csv("test.csv")) // print(pa.csv.read_csv("test.csv"))
match &self.ctx.bindings[*index].kind { match &self.ctx.bindings[*index].kind {
BindingKind::Importation(Importation { name, full_name }) BindingKind::Importation(import) => {
| BindingKind::SubmoduleImportation(SubmoduleImportation { name, full_name }) => let name = import.name;
{ let full_name = import.full_name;
let has_alias = full_name let has_alias = full_name
.split('.') .split('.')
.last() .last()
.map(|segment| &segment != name) .map(|segment| segment != name)
.unwrap_or_default(); .unwrap_or_default();
if has_alias { if has_alias {
// Mark the sub-importation as used. // 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 let has_alias = full_name
.split('.') .split('.')
.last() .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(); .unwrap_or_default();
if has_alias { if has_alias {
// Mark the sub-importation as used. // Mark the sub-importation as used.
@ -4665,10 +4688,8 @@ impl<'a> Checker<'a> {
// Grab the existing bound __all__ values. // Grab the existing bound __all__ values.
if let StmtKind::AugAssign { .. } = &parent.node { if let StmtKind::AugAssign { .. } = &parent.node {
if let Some(index) = scope.get("__all__") { if let Some(index) = scope.get("__all__") {
if let BindingKind::Export(Export { names: existing }) = if let BindingKind::Export(export) = &self.ctx.bindings[*index].kind {
&self.ctx.bindings[*index].kind names.extend(&export.names);
{
names.extend_from_slice(existing);
} }
} }
} }
@ -4693,7 +4714,7 @@ impl<'a> Checker<'a> {
self.add_binding( self.add_binding(
id, id,
Binding { Binding {
kind: BindingKind::Export(Export { names: all_names }), kind: BindingKind::Export(Box::new(Export { names: all_names })),
runtime_usage: None, runtime_usage: None,
synthetic_usage: None, synthetic_usage: None,
typing_usage: None, typing_usage: None,
@ -4981,7 +5002,7 @@ impl<'a> Checker<'a> {
.get("__all__") .get("__all__")
.map(|index| &self.ctx.bindings[*index]) .map(|index| &self.ctx.bindings[*index])
.and_then(|binding| match &binding.kind { .and_then(|binding| match &binding.kind {
BindingKind::Export(Export { names }) => Some((names, binding.range)), BindingKind::Export(export) => Some((&export.names, binding.range)),
_ => None, _ => None,
}); });
@ -5013,7 +5034,7 @@ impl<'a> Checker<'a> {
.get("__all__") .get("__all__")
.map(|index| &self.ctx.bindings[*index]) .map(|index| &self.ctx.bindings[*index])
.and_then(|binding| match &binding.kind { .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, _ => None,
}); });
@ -5223,14 +5244,9 @@ impl<'a> Checker<'a> {
let binding = &self.ctx.bindings[*index]; let binding = &self.ctx.bindings[*index];
let full_name = match &binding.kind { let full_name = match &binding.kind {
BindingKind::Importation(Importation { full_name, .. }) => full_name, BindingKind::Importation(import) => import.full_name,
BindingKind::FromImportation(FromImportation { full_name, .. }) => { BindingKind::FromImportation(import) => import.full_name.as_str(),
full_name.as_str() BindingKind::SubmoduleImportation(import) => import.full_name,
}
BindingKind::SubmoduleImportation(SubmoduleImportation {
full_name,
..
}) => full_name,
_ => continue, _ => continue,
}; };

View File

@ -51,9 +51,9 @@ impl Violation for RuntimeImportInTypeCheckingBlock {
/// TCH004 /// TCH004
pub fn runtime_import_in_type_checking_block(binding: &Binding) -> Option<Diagnostic> { pub fn runtime_import_in_type_checking_block(binding: &Binding) -> Option<Diagnostic> {
let full_name = match &binding.kind { let full_name = match &binding.kind {
BindingKind::Importation(Importation { full_name, .. }) => full_name, BindingKind::Importation(import) => import.full_name,
BindingKind::FromImportation(FromImportation { full_name, .. }) => full_name.as_str(), BindingKind::FromImportation(import) => import.full_name.as_str(),
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => full_name, BindingKind::SubmoduleImportation(import) => import.full_name,
_ => return None, _ => return None,
}; };

View File

@ -161,66 +161,67 @@ impl Violation for TypingOnlyStandardLibraryImport {
/// Return `true` if `this` is implicitly loaded via importing `that`. /// Return `true` if `this` is implicitly loaded via importing `that`.
fn is_implicit_import(this: &Binding, that: &Binding) -> bool { fn is_implicit_import(this: &Binding, that: &Binding) -> bool {
match &this.kind { true
BindingKind::Importation(Importation { // match &this.kind {
full_name: this_name, // BindingKind::Importation(Importation {
.. // full_name: this_name,
}) // ..
| BindingKind::SubmoduleImportation(SubmoduleImportation { // })
name: this_name, .. // | BindingKind::SubmoduleImportation(SubmoduleImportation {
}) => match &that.kind { // name: this_name, ..
BindingKind::FromImportation(FromImportation { // }) => match &that.kind {
full_name: that_name, // BindingKind::FromImportation(FromImportation {
.. // full_name: that_name,
}) => { // ..
// Ex) `pkg.A` vs. `pkg` // }) => {
this_name // // Ex) `pkg.A` vs. `pkg`
.rfind('.') // this_name
.map_or(false, |i| this_name[..i] == *that_name) // .rfind('.')
} // .map_or(false, |i| this_name[..i] == *that_name)
BindingKind::Importation(Importation { // }
full_name: that_name, // BindingKind::Importation(Importation {
.. // full_name: that_name,
}) // ..
| BindingKind::SubmoduleImportation(SubmoduleImportation { // })
name: that_name, .. // | BindingKind::SubmoduleImportation(SubmoduleImportation {
}) => { // name: that_name, ..
// Ex) `pkg.A` vs. `pkg.B` // }) => {
this_name == that_name // // Ex) `pkg.A` vs. `pkg.B`
} // this_name == that_name
_ => false, // }
}, // _ => false,
BindingKind::FromImportation(FromImportation { // },
full_name: this_name, // BindingKind::FromImportation(FromImportation {
.. // full_name: this_name,
}) => match &that.kind { // ..
BindingKind::Importation(Importation { // }) => match &that.kind {
full_name: that_name, // BindingKind::Importation(Importation {
.. // full_name: that_name,
}) // ..
| BindingKind::SubmoduleImportation(SubmoduleImportation { // })
name: that_name, .. // | BindingKind::SubmoduleImportation(SubmoduleImportation {
}) => { // name: that_name, ..
// Ex) `pkg.A` vs. `pkg` // }) => {
this_name // // Ex) `pkg.A` vs. `pkg`
.rfind('.') // this_name
.map_or(false, |i| &this_name[..i] == *that_name) // .rfind('.')
} // .map_or(false, |i| &this_name[..i] == *that_name)
BindingKind::FromImportation(FromImportation { // }
full_name: that_name, // BindingKind::FromImportation(FromImportation {
.. // full_name: that_name,
}) => { // ..
// Ex) `pkg.A` vs. `pkg.B` // }) => {
this_name.rfind('.').map_or(false, |i| { // // Ex) `pkg.A` vs. `pkg.B`
that_name // this_name.rfind('.').map_or(false, |i| {
.rfind('.') // that_name
.map_or(false, |j| this_name[..i] == that_name[..j]) // .rfind('.')
}) // .map_or(false, |j| this_name[..i] == that_name[..j])
} // })
_ => false, // }
}, // _ => false,
_ => false, // },
} // _ => false,
// }
} }
/// Return `true` if `name` is exempt from typing-only enforcement. /// 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 { let full_name = match &binding.kind {
BindingKind::Importation(Importation { full_name, .. }) => full_name, BindingKind::Importation(import) => import.full_name,
BindingKind::FromImportation(FromImportation { full_name, .. }) => full_name.as_str(), BindingKind::FromImportation(import) => import.full_name.as_str(),
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => full_name, BindingKind::SubmoduleImportation(import) => import.full_name,
_ => return None, _ => return None,
}; };

View File

@ -85,11 +85,8 @@ pub fn check_call(checker: &mut Checker, func: &Expr) {
// irrelevant bindings (like non-Pandas imports). // irrelevant bindings (like non-Pandas imports).
if let ExprKind::Name { id, .. } = &value.node { if let ExprKind::Name { id, .. } = &value.node {
if checker.ctx.find_binding(id).map_or(true, |binding| { if checker.ctx.find_binding(id).map_or(true, |binding| {
if let BindingKind::Importation(Importation { if let BindingKind::Importation(import) = &binding.kind {
full_name: module, .. import.full_name != "pandas"
}) = &binding.kind
{
module != &"pandas"
} else { } else {
matches!( matches!(
binding.kind, binding.kind,

View File

@ -59,45 +59,28 @@ impl<'a> Binding<'a> {
pub fn redefines(&self, existing: &'a Binding) -> bool { pub fn redefines(&self, existing: &'a Binding) -> bool {
match &self.kind { match &self.kind {
BindingKind::Importation(Importation { full_name, .. }) => { BindingKind::Importation(import) => {
if let BindingKind::SubmoduleImportation(SubmoduleImportation { if let BindingKind::SubmoduleImportation(existing) = &existing.kind {
full_name: existing, return import.full_name == existing.full_name;
..
}) = &existing.kind
{
return full_name == existing;
} }
} }
BindingKind::FromImportation(FromImportation { full_name, .. }) => { BindingKind::FromImportation(import) => {
if let BindingKind::SubmoduleImportation(SubmoduleImportation { if let BindingKind::SubmoduleImportation(existing) = &existing.kind {
full_name: existing, return import.full_name == existing.full_name;
..
}) = &existing.kind
{
return full_name == existing;
} }
} }
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => { BindingKind::SubmoduleImportation(import) => match &existing.kind {
match &existing.kind { BindingKind::Importation(existing) => {
BindingKind::Importation(Importation { return import.full_name == existing.full_name;
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(existing) => {
return import.full_name == existing.full_name;
}
BindingKind::FromImportation(existing) => {
return import.full_name == existing.full_name;
}
_ => {}
},
BindingKind::Annotation => { BindingKind::Annotation => {
return false; return false;
} }
@ -259,11 +242,11 @@ pub enum BindingKind<'a> {
Builtin, Builtin,
ClassDefinition, ClassDefinition,
FunctionDefinition, FunctionDefinition,
Export(Export<'a>), Export(Box<Export<'a>>),
FutureImportation, FutureImportation,
Importation(Importation<'a>), Importation(Box<Importation<'a>>),
FromImportation(FromImportation<'a>), FromImportation(Box<FromImportation<'a>>),
SubmoduleImportation(SubmoduleImportation<'a>), SubmoduleImportation(Box<SubmoduleImportation<'a>>),
} }
bitflags! { bitflags! {

View File

@ -166,10 +166,8 @@ impl<'a> Context<'a> {
return None; return None;
}; };
match &binding.kind { match &binding.kind {
BindingKind::Importation(Importation { BindingKind::Importation(import) => {
full_name: name, .. let name = import.full_name;
})
| BindingKind::SubmoduleImportation(SubmoduleImportation { name, .. }) => {
if name.starts_with('.') { if name.starts_with('.') {
if let Some(module) = &self.module_path { if let Some(module) = &self.module_path {
let mut source_path = from_relative_import(module, name); let mut source_path = from_relative_import(module, name);
@ -188,9 +186,28 @@ impl<'a> Context<'a> {
Some(source_path) Some(source_path)
} }
} }
BindingKind::FromImportation(FromImportation { BindingKind::SubmoduleImportation(import) => {
full_name: name, .. 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 name.starts_with('.') {
if let Some(module) = &self.module_path { if let Some(module) = &self.module_path {
let mut source_path = from_relative_import(module, name); let mut source_path = from_relative_import(module, name);
@ -243,16 +260,19 @@ impl<'a> Context<'a> {
// Ex) Given `module="sys"` and `object="exit"`: // Ex) Given `module="sys"` and `object="exit"`:
// `import sys` -> `sys.exit` // `import sys` -> `sys.exit`
// `import sys as sys2` -> `sys2.exit` // `import sys as sys2` -> `sys2.exit`
BindingKind::Importation(Importation { name, full_name }) => { BindingKind::Importation(import) => {
if full_name == &module { if import.full_name == module {
// Verify that `sys` isn't bound in an inner scope. // Verify that `sys` isn't bound in an inner scope.
if self if self
.scopes() .scopes()
.take(scope_index) .take(scope_index)
.all(|scope| scope.get(name).is_none()) .all(|scope| scope.get(import.name).is_none())
{ {
if let Some(source) = binding.source { 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"`: // Ex) Given `module="os.path"` and `object="join"`:
// `from os.path import join` -> `join` // `from os.path import join` -> `join`
// `from os.path import join as join2` -> `join2` // `from os.path import join as join2` -> `join2`
BindingKind::FromImportation(FromImportation { name, full_name }) => { BindingKind::FromImportation(import) => {
if let Some((target_module, target_member)) = full_name.split_once('.') { if let Some((target_module, target_member)) =
import.full_name.split_once('.')
{
if target_module == module && target_member == member { if target_module == module && target_member == member {
// Verify that `join` isn't bound in an inner scope. // Verify that `join` isn't bound in an inner scope.
if self if self
.scopes() .scopes()
.take(scope_index) .take(scope_index)
.all(|scope| scope.get(name).is_none()) .all(|scope| scope.get(import.name).is_none())
{ {
if let Some(source) = binding.source { 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"`: // Ex) Given `module="os"` and `object="name"`:
// `import os.path ` -> `os.name` // `import os.path ` -> `os.name`
BindingKind::SubmoduleImportation(SubmoduleImportation { name, .. }) => { BindingKind::SubmoduleImportation(import) => {
if name == &module { if import.name == module {
// Verify that `os` isn't bound in an inner scope. // Verify that `os` isn't bound in an inner scope.
if self if self
.scopes() .scopes()
.take(scope_index) .take(scope_index)
.all(|scope| scope.get(name).is_none()) .all(|scope| scope.get(import.name).is_none())
{ {
if let Some(source) = binding.source { if let Some(source) = binding.source {
return Some((self.stmts[source], format!("{name}.{member}"))); return Some((
self.stmts[source],
format!("{}.{member}", import.name),
));
} }
} }
} }