Skip to content

Add ast ident iterator #6100

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

Closed
wants to merge 52 commits into from

Conversation

Ryan1729
Copy link
Contributor

@Ryan1729 Ryan1729 commented Oct 1, 2020

While working on #6086 which is a PR meant to address #6039, I found that I needed a way to iterate through the identifiers in an expression. Implementing an Ident iterator has turned out to be sufficiently complicated that I thought it would be nicer for reviewers if those changes were in a separate PR. This is that PR.

changelog: none

@rust-highfive
Copy link

r? @phansch

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Oct 1, 2020
@phansch
Copy link
Member

phansch commented Oct 6, 2020

Thanks for the PR! Unfortunately, I'm not too familiar with this part of the code, so maybe r? @flip1995

Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So before reviewing all of this: IIUC the goal of this is to get an iterator over all idents in an expression. Is there a reason, that you need lazy evaluation here? Otherwise we could just use a Visitor, which collects every Ident in a Vec and then just turns this Vec into an iterator.

Downside is that you have to collect all Idents and have a worse performance if you often want to stop iterating after a few steps.

The advantage is, that you don't have to implement all of the expr/item/ty/... handling yourself, since it is already implemented by the Visitor.

Comment on lines 69 to 49
/// This is a convenience method to help with type inference.
fn new_p(expr: &'expr P<Expr>) -> Self {
Self::new(expr)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an example. where this would be necessary. Using P<_> in a type signature should not be possible, since it implements Deref.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given exprs is a &Vec<P<Expr>>,

exprs.iter()
    .flat_map(ExprIdentIter::new_p)

compiles, while using ExprIdentIter::new does not:

exprs.iter()
    .flat_map(ExprIdentIter::new)

IIRC this compiles:

exprs.iter()
    .flat_map(|e| ExprIdentIter::new(e))

So ExprIdentIter::new_p allows skipping writing the closure.
I'm willing to believe there might be a better way to do this. Maybe making ExprIdentIter::new generic or something like that?

@Ryan1729
Copy link
Contributor Author

So before reviewing all of this: IIUC the goal of this is to get an iterator over all idents in an expression.

That is correct. And the main reason we want an is to create suggestions containing an expression with some of the Idents swapped. Specifically this code in #6086, (currently a WIP) uses such an iterator:

Is there a reason, that you need lazy evaluation here? Otherwise we could just use a Visitor, which collects every Ident in a Vec and then just turns this Vec into an iterator.

Downside is that you have to collect all Idents and have a worse performance if you often want to stop iterating after a few steps.

The advantage is, that you don't have to implement all of the expr/item/ty/... handling yourself, since it is already implemented by the Visitor.

Hmm. Well, the part that actually creates the suggestion can stop early. But at least for the purposes of #6086, that iteration would be preceded by some form of full iteration over the expression in question anyway, so maybe that savings would be insignificant. O(n + n / 2) is still O(n).

Given how much work handling all the possibilities myself has been so far, using a Visitor sounds like it would be worth doing, given we aren't positive the perf difference. If we only expose an Iterator trait object then if it turns out that laziness is worth doing we can change it without affecting the user(s) of the iterator. So I think I'll given switching to using a Visitor and walk_expr a go.

@Ryan1729 Ryan1729 force-pushed the add-ast-ident-iterator branch from 744e8fa to 5ff2cd7 Compare October 11, 2020 04:42
@Ryan1729 Ryan1729 force-pushed the add-ast-ident-iterator branch from 5ff2cd7 to 0da001f Compare October 12, 2020 21:45
@Ryan1729
Copy link
Contributor Author

Okay, I feel silly now for not using Visitor from the start, given how simple the code has now become.

@Ryan1729 Ryan1729 marked this pull request as ready for review October 12, 2020 22:44
Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the code is now that simple, I think you can squash it into one commit and include it in the other PR?

@Ryan1729
Copy link
Contributor Author

Since the code is now that simple, I think you can squash it into one commit and include it in the other PR?

I'll do that. Thanks for all your help simplifying the code!

@Ryan1729 Ryan1729 closed this Oct 14, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants