Skip to content
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

ast::mut_visit::MutVisitor and ast::visit::Visitor do not have corresponding methods for all their methods #127615

Open
1 of 5 tasks
oli-obk opened this issue Jul 11, 2024 · 12 comments
Labels
A-ast Area: AST A-technical-debt Area: Internal cleanup work C-cleanup Category: PRs that clean code up or issues documenting cleanup. E-medium Call for participation: Medium difficulty. Experience needed to fix: Intermediate. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@oli-obk
Copy link
Contributor

oli-obk commented Jul 11, 2024

In contrast to the MIR mut and immut visitors

make_mir_visitor!(Visitor,);
make_mir_visitor!(MutVisitor, mut);

which are generated from a single macro, and are thus exactly the same except for mutation, the ast visitors are each handwritten. Their method naming scheme doesn't even match up, so changing from a Visitor to a MutVisitor requires extensive changes.

Work items

  • Adjust names so everything has the visit_* vs walk_* naming scheme
  • Give every MutVisitor::visit_* method a corresponding flat_map_* method. E-medium Call for participation: Medium difficulty. Experience needed to fix: Intermediate.
    • we can make it so implementors can override either visit_foo or flat_map_foo without there being problems. The walk_bar functions must invoke flat_map_foo, so that they can pick up on more/fewer items being produced. So walk_flat_map_foo (which only ever maps to a single output element) needs to invoke visit_foo, not walk_foo. Otherwise overriding visit_foo will do nothing.
    • This should be using macros similar to what [WIP] Try optimizing noop AST mut visiting #127371 did, so you don't repeat yourself
  • (Optional): move all the walk_ functions to defaulted methods on the trait (not sure this should be done, discuss on zulip first!) discussed, should not be done
  • Give every MutVisitor::visit_* method a corresponding Visitor method and vice versa E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
  • Create a macro that generates both visitors, including the walk_ functions in one go, just like with the MIR visitors E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot.

Previous work

@oli-obk oli-obk added C-cleanup Category: PRs that clean code up or issues documenting cleanup. E-medium Call for participation: Medium difficulty. Experience needed to fix: Intermediate. A-technical-debt Area: Internal cleanup work labels Jul 11, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jul 11, 2024
@oli-obk oli-obk added the E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. label Jul 11, 2024
bors added a commit to rust-lang-ci/rust that referenced this issue Jul 13, 2024
Make ast `MutVisitor` have the same method name and style as `Visitor`

It doesn't map 100% because some `MutVisitor` methods can filter or even expand to multiple items, but consistency seems nicer.

The last commit showcases how similar they are by changing ast validation to a `MutVisitor` (without actually doing any mutation yet). My plan is to replace all nodes that support it with error nodes if validation failed on them. This allows ast lowering to just assume things are error or valid, and avoids having to redo some checks, delaying bugs or checking the global error counter.

tracking issue: rust-lang#127615
bors added a commit to rust-lang-ci/rust that referenced this issue Jul 22, 2024
Make ast `MutVisitor` have the same method name and style as `Visitor`

It doesn't map 100% because some `MutVisitor` methods can filter or even expand to multiple items, but consistency seems nicer.

tracking issue: rust-lang#127615
bors added a commit to rust-lang-ci/rust that referenced this issue Jul 23, 2024
…nkov

Make ast `MutVisitor` have the same method name and style as `Visitor`

It doesn't map 100% because some `MutVisitor` methods can filter or even expand to multiple items, but consistency seems nicer.

tracking issue: rust-lang#127615
bors added a commit to rust-lang-ci/rust that referenced this issue Jul 24, 2024
…nkov

Make ast `MutVisitor` have the same method name and style as `Visitor`

It doesn't map 100% because some `MutVisitor` methods can filter or even expand to multiple items, but consistency seems nicer.

tracking issue: rust-lang#127615
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Jul 25, 2024
Make ast `MutVisitor` have the same method name and style as `Visitor`

It doesn't map 100% because some `MutVisitor` methods can filter or even expand to multiple items, but consistency seems nicer.

tracking issue: rust-lang/rust#127615
flip1995 pushed a commit to flip1995/rust-clippy that referenced this issue Jul 25, 2024
Make ast `MutVisitor` have the same method name and style as `Visitor`

It doesn't map 100% because some `MutVisitor` methods can filter or even expand to multiple items, but consistency seems nicer.

tracking issue: rust-lang/rust#127615
@GrigorenkoPV
Copy link
Contributor

Give every MutVisitor::visit_* method a corresponding Visitor method and vice versa

  • Missing in Visitor::visit_*
    • angle_bracketed_parameter_data
    • coroutine_kind
    • fn_decl
    • foreign_mod
    • id
    • macro_def
    • meta_item
    • meta_list_item
    • mt
    • parenthesized_parameter_data
    • qself
    • span
    • where_clause
  • Missing in MutVisitor::visit_*
    • arm
    • assoc_item
    • enum_def
    • expr_field
    • expr_post
    • field_def
    • fn_ret_ty
    • foreign_item
    • generic_param
    • item
    • mac_def
    • param
    • pat_field
    • stmt
    • variant
    • variant_discr

All of these should be added, correct?

@oli-obk
Copy link
Contributor Author

oli-obk commented Jul 26, 2024

For the ones that only exist in Visitor but not in MutVisitor, it may be useful to see if anyone actually overrides these and potentially entirely remove them.

For the ones that only exist in MutVisitor but not Visitor, there are some that don't really make sense for Visitor, like the one for ids or the one for spans. There won't be any immutable visitors that just want to see all spans I think. So it seems ok to have such differences for leaf functions (where the Walker is a noop)

@oli-obk
Copy link
Contributor Author

oli-obk commented Jul 26, 2024

Also sometimes MutVisitor has things like ItemKind visiting, but not Item...

Looks like my idea was a bit naive. We basically need to analyze every missing method and see if there isn't one almost like it and if it can reasonably be refactored or if the mut visitor is just too different because of the mutation

@Borgerr
Copy link
Contributor

Borgerr commented Aug 3, 2024

Someone can correct me if I'm wrong, but I don't think claiming this issue is entirely appropriate, as it involves tracking sub-issues. I for one would be wanting to pick the low hanging fruit for the 4th suggestion for example, but leave the others alone.

@saethlin saethlin removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 4, 2024
@maxcabrajac
Copy link
Contributor

I think I can begin to implement the macro that generates both traits and walk_* functions by merging one function at a time and seek mentoring to unify the more complex walk functions as needed. I'm thinking about making the macro generate a module so the path to walk_* functions stays the same.

@maxcabrajac
Copy link
Contributor

maxcabrajac commented Aug 14, 2024

I did some digging and this is what I found out:

  • Missing in Visitor::visit_*
    • coroutine_kind
    • id
    • meta_item
    • meta_list_item
    • span
    • There is a walk_ but no visit_
      • fn_decl
      • qself
        • Normally the caller unwraps options, but not here (?)
    • Visitors do the same manually
      • angle_bracketed_parameter_data
      • parenthesized_parameter_data
      • foreign_mod
      • mt
      • where_clause
  • Missing in MutVisitor::visit_*
    • enum_def
      • MutVisitors do the same manually
    • expr_post
      • Noop on default implementation
      • Only implementer is rustc_lint/src/early.rs. Looking at it, I think this might be a missplaced function as they have a bunch of *_post functions.
    • variant_discr
      • Default implementation is to delegate to visit_anon_const
      • Only implementer is rustc_resolve/src/late.rs. They use it to inject a AnonConstKind for a proper resolver. It seems like proper use.
    • fn_ret_ty
      • There is a walk_ but no visit_
    • Methods that already have a flat_map_ variant (also these are all flat_map_*s that exist (?)):
      • arm
      • assoc_item
      • expr_field
      • field_def
      • foreign_item
      • generic_param
      • item
      • param
      • pat_field
      • stmt
      • variant
  • Visitor::mac_def and MutVisitor::macro_def
    • Signatures make me think they are supposed to be the same, but mac_def is a noop while macro_def is not (it recurses by using non-trait visit_ functions)
  • Some functions have aditional parameters on Visitor
    • lifetime
    • path
    • use_tree
  • Visitor::visit_precise_capturing_arg doesn't return V::Result. bug?

@obeis obeis removed their assignment Aug 20, 2024
@maxcabrajac
Copy link
Contributor

maxcabrajac commented Aug 20, 2024

I was digging around to find out what to do with methods that have a flat_map_* variant and got confused... Why do flat_map_*s exist? All of them are just one to one conversions (their signatures are simalar to: fn(_: T) -> SmallVec<[T; 1]>). Is there a reason not to have just visit_*s and do something like what's done in mut_visit::{visit_vec, visit_thin_vec} or list.iter_mut().map(|t| vis.visit_t(t))?

@oli-obk
Copy link
Contributor Author

oli-obk commented Aug 21, 2024

There are implementors of MutVisitor that produce multiple items. E.g. when expanding a macro in item position, it may yield multiple items

@maxcabrajac
Copy link
Contributor

maxcabrajac commented Aug 21, 2024

Ohhh, now I get it. Sorry, I didn't read the docs for SmallVec well enough.

@noahmbright
Copy link
Contributor

Is there a master list of what visit_* methods exist? If there isn't but there's a way to find all of them I could go through and do that. I think that would make it easier to track progress on each flat_map and if either the MutVisitor or Visitor method needs implemented. Without a centralized list I'm having trouble telling what's left, especially if the MutVisitor should be treated differently from the immutable one

@maxcabrajac
Copy link
Contributor

maxcabrajac commented Sep 23, 2024

Hi @noahmbright!
Using rustdoc is a good way of getting a master list of what each trait offers.
I did a bunch of work in #128974 and tackled the last two tasks of this issue (you can have look at it there, your input would be greatly appreciated!). One of the things I did is a macro that quickly writes flat_map and walk_flat_map implementations, so doing the first task after #128974 is merged would be more of a chore than anything.

I didn't do it immediately as I think it deserves a bit more discussion. Sorry for not starting it until now. =/

I noticed that every type whose visit_ has a flat_map_ variant in MutVisitor is always stored in the AST as a list, so 1-to-many conversions make perfect sense. On the other hand, types whose visit_ doesn't have a flat_map_ variant are stored directly most of the time, so 1-to-1 conversions are required.
At first, I thought that adding flat_map_ to anything that is stored at least once in a list and use flat_map_ whenever possible would be a good idea, but the very next day I thought that this way of doing things requires the implementer to know of this distinction between 1-to-1 visit_ functions and 1-to-many flat_map_s and to know when each of them is be called by the parent node's walk_.
Should we make the distinction between required 1-to-1 conversions and possible 1-to-many conversions? Or should we leave it as is, allowing flat_map_ only when it is always used?

@lucarlig
Copy link
Contributor

not entirely clear what is left to do, which easy issue is still left, and how can I claim it?

@jieyouxu jieyouxu added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. labels Nov 14, 2024
@jieyouxu jieyouxu added the A-ast Area: AST label Nov 14, 2024
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Nov 19, 2024
…chenkov

Add `visit` methods to ast nodes that already have `walk`s on ast visitors

Some `walk` functions are called directly, because there were no correspondent visit functions.

related to rust-lang#128974 & rust-lang#127615

r? `@petrochenkov`
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Nov 20, 2024
Rollup merge of rust-lang#133188 - maxcabrajac:walk_no_visit, r=petrochenkov

Add `visit` methods to ast nodes that already have `walk`s on ast visitors

Some `walk` functions are called directly, because there were no correspondent visit functions.

related to rust-lang#128974 & rust-lang#127615

r? `@petrochenkov`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Nov 21, 2024
Add visits to nodes that already have flat_maps in ast::MutVisitor

This PR aims to add `visit_` methods for every node that has a `flat_map_` in MutVisitor, giving implementers free choice over overriding `flat_map` for 1-to-n conversions or `visit` for a 1-to-1.

There is one major problem: `flat_map_stmt`.
While all other default implementations of `flat_map`s are 1-to-1 conversion, as they either only call visits or a internal 1-to-many conversions are natural, `flat_map_stmt` doesn't follow this pattern.

`flat_map_stmt`'s default implementation is a 1-to-n conversion that panics if n > 1 (effectively being a 1-to-[0;1]). This means that it cannot be used as is for a default `visit_stmt`, which would be required to be a 1-to-1.

Implementing `visit_stmt` without runtime checks would require it to reach over a potential `flat_map_item` or `filter_map_expr` overrides and call for their `visit` counterparts directly.
Other than that, if we want to keep the behavior of `flat_map_stmt` it cannot call `visit_stmt` internally.

To me, it seems reasonable to make all default implementations 1-to-1 conversions and let implementers handle `visit_stmt` if they need it, but I don't know if calling `visit` directly when a 1-to-1 is required is ok or not.

related to rust-lang#128974 & rust-lang#127615

r? `@petrochenkov`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Nov 21, 2024
Add visits to nodes that already have flat_maps in ast::MutVisitor

This PR aims to add `visit_` methods for every node that has a `flat_map_` in MutVisitor, giving implementers free choice over overriding `flat_map` for 1-to-n conversions or `visit` for a 1-to-1.

There is one major problem: `flat_map_stmt`.
While all other default implementations of `flat_map`s are 1-to-1 conversion, as they either only call visits or a internal 1-to-many conversions are natural, `flat_map_stmt` doesn't follow this pattern.

`flat_map_stmt`'s default implementation is a 1-to-n conversion that panics if n > 1 (effectively being a 1-to-[0;1]). This means that it cannot be used as is for a default `visit_stmt`, which would be required to be a 1-to-1.

Implementing `visit_stmt` without runtime checks would require it to reach over a potential `flat_map_item` or `filter_map_expr` overrides and call for their `visit` counterparts directly.
Other than that, if we want to keep the behavior of `flat_map_stmt` it cannot call `visit_stmt` internally.

To me, it seems reasonable to make all default implementations 1-to-1 conversions and let implementers handle `visit_stmt` if they need it, but I don't know if calling `visit` directly when a 1-to-1 is required is ok or not.

related to rust-lang#128974 & rust-lang#127615

r? ``@petrochenkov``
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Nov 21, 2024
Rollup merge of rust-lang#133153 - maxcabrajac:flat_maps, r=petrochenkov

Add visits to nodes that already have flat_maps in ast::MutVisitor

This PR aims to add `visit_` methods for every node that has a `flat_map_` in MutVisitor, giving implementers free choice over overriding `flat_map` for 1-to-n conversions or `visit` for a 1-to-1.

There is one major problem: `flat_map_stmt`.
While all other default implementations of `flat_map`s are 1-to-1 conversion, as they either only call visits or a internal 1-to-many conversions are natural, `flat_map_stmt` doesn't follow this pattern.

`flat_map_stmt`'s default implementation is a 1-to-n conversion that panics if n > 1 (effectively being a 1-to-[0;1]). This means that it cannot be used as is for a default `visit_stmt`, which would be required to be a 1-to-1.

Implementing `visit_stmt` without runtime checks would require it to reach over a potential `flat_map_item` or `filter_map_expr` overrides and call for their `visit` counterparts directly.
Other than that, if we want to keep the behavior of `flat_map_stmt` it cannot call `visit_stmt` internally.

To me, it seems reasonable to make all default implementations 1-to-1 conversions and let implementers handle `visit_stmt` if they need it, but I don't know if calling `visit` directly when a 1-to-1 is required is ok or not.

related to rust-lang#128974 & rust-lang#127615

r? ``@petrochenkov``
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ast Area: AST A-technical-debt Area: Internal cleanup work C-cleanup Category: PRs that clean code up or issues documenting cleanup. E-medium Call for participation: Medium difficulty. Experience needed to fix: Intermediate. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

10 participants