-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: Use QualifiedName
for Imported::call_path
#10214
Conversation
bcb457d
to
71dd02a
Compare
bd43f3d
to
293adf4
Compare
293adf4
to
ab84658
Compare
CodSpeed Performance ReportMerging #10214 will not alter performanceComparing Summary
|
|
89a3488
to
41b8fd2
Compare
QualifiedName
for Imported::call_path
41b8fd2
to
a852379
Compare
ee0c9d8
to
87260fb
Compare
87260fb
to
9b04828
Compare
Self { | ||
segments: iter.into_iter().collect(), | ||
impl Display for QualifiedName<'_> { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inlined from format_qualified_name_segments
. We no longer need format_qualified_name_segments
because the code that used Box<[&'astr]>
can now call into this display implementation.
w.write_char('.')?; | ||
impl<'a> UnqualifiedName<'a> { | ||
/// Convert an `Expr` to its [`UnqualifiedName`] (like `["typing", "List"]`). | ||
pub fn from_expr(expr: &'a Expr) -> Option<Self> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inlined from collect_segments
(see separate commit)
crates/ruff_python_ast/src/name.rs
Outdated
let mut segments = Vec::with_capacity(SMALL_LEN * 2); | ||
|
||
let mut current = &*attr8.value; | ||
|
||
loop { | ||
current = match current { | ||
Expr::Attribute(attr) => { | ||
segments.push(attr.attr.as_str()); | ||
&*attr.value | ||
} | ||
Expr::Name(nodes::ExprName { id, .. }) => { | ||
segments.push(id.as_str()); | ||
break; | ||
} | ||
_ => break, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I rewrote this to no longer require recursion (which creates new SegmentsVec
s internally, which seems unnecessary when we know that we need a Vec
anyway).
fn call_path(&self) -> &[&'a str] { | ||
self.qualified_name.as_ref() | ||
fn qualified_name(&self) -> &QualifiedName<'a> { | ||
&self.qualified_name | ||
} | ||
|
||
/// For example, given `import foo.bar`, returns `["foo"]`. | ||
fn module_name(&self) -> &[&'a str] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice if we could return QualifiedNameRef
or similar from here because the module name is a qualified name too. But I consider this out of the scope of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
w00t! LGTM!
struct SegmentsStack<'a> { | ||
segments: [&'a str; SMALL_LEN], | ||
len: usize, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible arrayvec
could simplify things a bit here, although it may have the same issue as smallvec
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, the arrayvec
crate doesn't support the most complex operation, extending from an Iterator. That's why I think its use is limited. The main advantage I see is that it avoids initializing unused memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gave it a quick try. Funny enough, it has a variance issue, but it manifests differently than smallvec
heap.as_slice(), | ||
&["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"] | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice tests. :)
) ## Summary When you try to remove an internal representation leaking into another type and end up rewriting a simple version of `smallvec`. The goal of this PR is to replace the `Box<[&'a str]>` with `Box<QualifiedName>` to avoid that the internal `QualifiedName` representation leaks (and it gives us a nicer API too). However, doing this when `QualifiedName` uses `SmallVec` internally gives us all sort of funny lifetime errors. I was lost but @BurntSushi came to rescue me. He figured out that `smallvec` has a variance problem which is already tracked in servo/rust-smallvec#146 To fix the variants problem, I could use the smallvec-2-alpha-4 or implement our own smallvec. I went with implementing our own small vec for this specific problem. It obviously isn't as sophisticated as smallvec (only uses safe code), e.g. it doesn't perform any size optimizations, but it does its job. Other changes: * Removed `Imported::qualified_name` (the version that returns a `String`). This can be replaced by calling `ToString` on the qualified name. * Renamed `Imported::call_path` to `qualified_name` and changed its return type to `&QualifiedName`. * Renamed `QualifiedName::imported` to `user_defined` which is the more common term when talking about builtins vs the rest/user defined functions. ## Test plan `cargo test`
Summary
When you try to remove an internal representation leaking into another type and end up rewriting a simple version of
smallvec
.The goal of this PR is to replace the
Box<[&'a str]>
withBox<QualifiedName>
to avoid that the internalQualifiedName
representation leaks (and it gives us a nicer API too). However, doing this whenQualifiedName
usesSmallVec
internally gives us all sort of funny lifetime errors. I was lost but @BurntSushi came to rescue me. He figured out thatsmallvec
has a variance problem which is already tracked in servo/rust-smallvec#146To fix the variants problem, I could use the smallvec-2-alpha-4 or implement our own smallvec. I went with implementing our own small vec for this specific problem. It obviously isn't as sophisticated as smallvec (only uses safe code), e.g. it doesn't perform any size optimizations, but it does its job.
Other changes:
Imported::qualified_name
(the version that returns aString
). This can be replaced by callingToString
on the qualified name.Imported::call_path
toqualified_name
and changed its return type to&QualifiedName
.QualifiedName::imported
touser_defined
which is the more common term when talking about builtins vs the rest/user defined functions.Test plan
cargo test