-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Make some traversable types generic over interner #108214
Conversation
This PR changes MIR cc @oli-obk, @RalfJung, @JakobDegen, @davidtwco, @celinval, @vakaras Some changes occurred to the CTFE / Miri engine cc @rust-lang/miri Some changes occured in cc @BoxyUwU These commits modify compiler targets. These commits modify the If this was intentional then you can ignore this comment. |
dc58d23
to
0330754
Compare
☔ The latest upstream changes (presumably #108340) made this pull request unmergeable. Please resolve the merge conflicts. |
0330754
to
784870c
Compare
Some changes occurred to the core trait solver cc @rust-lang/initiative-trait-system-refactor Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
I've reworked this PR to use (in a8cd76c9d450abd0b78f0fbcf9268677fd07d591) the genius suggestion made by @lcnr in the Zulip topic for my (now closed) associated MCP of an auto-trait together with auto-deref specialisation. This ensures that:
I think a perf run would now be wise. Maybe given the amount of thought @lcnr has put into this already, they're now the most suitable reviewer? I wanted to get your nod on that first though @oli-obk? |
@bors try @rust-timer queue I'll happily let lcnr take over this PR, but will review next week otherwise |
This comment has been minimized.
This comment has been minimized.
⌛ Trying commit 784870c3d73ee21f3d730a1406010f77620ea0d0 with merge 516caeb9588d175d929b03ef6889f0b43055f136... |
784870c
to
e1f6096
Compare
Thanks Oli. Unfortunately, I hadn't noticed your comment before I pushed a minor change to comments that I think cancelled the perf run? |
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
⌛ Trying commit e1f6096f7118020b355bdff7b4e2dd48d910825c with merge 3c471c0bbf60528fb31cc524fbb5a51c124d6fae... |
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (3c471c0bbf60528fb31cc524fbb5a51c124d6fae): comparison URL. Overall result: ❌ regressions - ACTION NEEDEDBenchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @bors rollup=never Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
|
I have a hunch the regressions will be down to some function calls that are now cross-crate no longer being inlined. Will dig deeper. |
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
⌛ Trying commit bf618ac with merge 1950270ad663a766750d9890629a5cd5abca197a... |
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (1950270ad663a766750d9890629a5cd5abca197a): comparison URL. Overall result: ❌✅ regressions and improvements - ACTION NEEDEDBenchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @bors rollup=never Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
|
Okay, so we're definitely moving in the right direction. Of the regressions that remain, 6/8 arose on the 6,221,122 ???:<rustc_middle::ty::Ty as rustc_type_ir::fold::TypeSuperFoldable<rustc_middle::ty::context::TyCtxt>>::super_fold_with::<rustc_infer::infer::resolve::OpportunisticVarResolver> 1,805,758 ???:<rustc_middle::ty::Ty as rustc_type_ir::fold::TypeFoldable<rustc_middle::ty::context::TyCtxt>>::try_fold_with::<rustc_infer::infer::resolve::OpportunisticVarResolver> 1,565,584 ???:<rustc_infer::infer::ShallowResolver>::fold_infer_ty 847,898 ???:<core::option::Option<alloc::rc::Rc<rustc_middle::traits::ObligationCauseCode>> as rustc_type_ir::fold::TypeFoldable<rustc_middle::ty::context::TyCtxt>>::try_fold_with::<rustc_infer::infer::resolve::OpportunisticVarResolver> 839,194 ???:<rustc_trait_selection::traits::fulfill::FulfillProcessor as rustc_data_structures::obligation_forest::ObligationProcessor>::process_obligation -837,429 ???:rustc_trait_selection::traits::wf::obligations 620,831 ???:<rustc_trait_selection::traits::wf::WfPredicates>::nominal_obligations_inner -460,969 ???:<rustc_infer::infer::resolve::OpportunisticVarResolver as rustc_type_ir::fold::FallibleTypeFolder<rustc_middle::ty::context::TyCtxt>>::try_fold_ty I'm pretty sure something here isn't getting inlined as it was before, but I'm really not sure what... I'll get a cross-compilation of a debug build going tomorrow so that I can hopefully glean something useful from the cachegrind line counts. |
Look in and around |
Okay, it's not due to inlining: That being the case, and these being minor regressions in secondary benchmarks, are we okay to mark this regression as triaged? |
Perhaps it'd be sensible to use an attribute on the |
I like that, but if it is a lot of implementation effort, maybe just hand-roll the impl |
@eggyal FYI: when a PR is ready for review, send a message containing |
Closing this as inactive. Feel free to reöpen this pr or create a new pr if you get the time to work on this. Thanks |
Apologies for the lack of attention on this—had a host of other things demanding my attention over these past months. I'm back on it now. I don't appear to have the option to reopen the PR—happy to create a new one, whatever is preferred? |
creating a new one is fine 👍 |
…pes_noop-traversable, r=<try> Automatically make trivial types noop-traversable This is a second reincarnation of rust-lang#108214 (or at least, what that PR ultimately became), the previous reincarnation in rust-lang#117620 having been closed accidentally. It may be easier to review by commit, albeit there are quite a few of them. ## Terminology I refer to: * folds and visits as "traversals" * the types that are folded or visited as "traversables" * the folders and visitors as "traversers" * traversables on which traversers can act as "interesting" (there are currently only five: binders, types, consts, regions and predicates) and all others as "trivial" (traversals of which are no-ops) * the `TypeFoldable` and `TypeVisitable` traits (and only these traits) as the "traversable traits" ## Content This PR: * introduces a macro, `rustc_type_ir::noop_if_trivially_traversable` that uses [auto-deref specialisation](http://lukaskalbertodt.github.io/2019/12/05/generalized-autoref-based-specialization.html) to: * perform a no-op traversal on values of type `T` if the interner implements `rustc_type_ir::TriviallyTraverses<T>` (thereby obviating all need for most trivial types to implement the traversable traits—and indeed such implementations are removed) or * delegate to the relevant traversable trait implementation on `T` otherwise; * introduces an auto-trait, `rustc_middle::ty::TriviallyTraversable`, that is then "unimplemented" on the interesting types (and thereby remains implemented only on, but on all, trivial types); * implements `rustc_type_ir::TriviallyTraverses<T>` on the `TyCtxt<'tcx>` interner for all `T: rustc_middle::ty::TriviallyTraversable` (thus ensuring that, for that interner at least, trivial types do not require implementations of the traversable traits); * updates the traversable traits' derive macros to: * skip fields that reference neither any generic type parameters nor, if present, the `'tcx` lifetime parameter * use the above specialisation macro when traversing fields * if the traversable is not parameterised by a `'tcx` lifetime, generate implementations that are generic over the interner; * replaces those derive macros' distinct helper attributes (introduced in rust-lang#108040) with a unified `#[skip_traversal]` helper attribute that requires a justifying reason to be provided (this does mean that the different types of traversal can no longer be independently skipped, but nowhere is that currently required or ever expected to be); * the derive macros by default refuse to be implemented on trivial types as specialisation usually negates any need—but this can be overridden with a `#[skip_traversal(impl_despite_trivial_because = "<reason>")]` attribute; * uses those derive macros in place of remaining usages of the `TrivialTypeTraversal` macros and some explicit implementations; and * a few other minor relevant refactorings. ## Commentary One limitation of auto-deref specialisation is that it cannot work for unconstrained generic types. Therefore, absent real specialisation, implementations of the traversable traits must constrain their generics: * by default, the derive macros constrain every field type `T` that references one or more generic type parameters to implementors of the relevant traversable trait—however this can be modified on a field (or variant) basis with a `#[skip_traversal(because_trivial)]` attribute so that instead the interner is constrained to implement `TriviallyTraverses<T>` (and the field is not traversed) * the constraints are applied to the field types rather than the generic type parameters to achieve a "[perfect derive](https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/)" that not only avoids having to propagate `#[skip_traversal]` annotations into wrapping types but also works with associated types and other esoteric situations—however this could result in trait solver cycles if interesting generic field types are one day involved in recursive type definitions; * for exceptionally rare cases where traversal of an item/variant/field should be a no-op despite it being (potentially, if generic) interesting, it can be annotated with the explicit and deliberately cumbersome `#[skip_traversal(despite_potential_miscompilation_because = "<reason>")]` (which produces a no-op without adding any constraint). * (the few remaining) explicit implementations of the traversable traits over generic types are similarly constrained * indeed, for generic tuples *all element types* must implement the trait—however, since (most) trivial types no longer do, this unfortunately means that the implementations are not applicable to tuples with trivial elements and hence some such tuples have been replaced with more concrete newtypes that have appropriate constraints: c5e9447 is a particularly hefty example of this (where tuples containing `Span` are replaced with `Spanned<T>` instead). r? `@lcnr` cc `@oli-obk` `@rustbot` label A-query-system T-compiler WG-trait-system-refactor
Implementations of the traversable traits (
TypeFoldable
andTypeVisitable
) that specify a concrete interner (TyCtxt
) can be defined in the crate that defines that interner (rustc_middle
) irrespective of whether the type for which the traits are being implemented are local or foreign to that crate—and indeed this is where many such implementations have historically been defined, even for simple types that otherwise have no dependency on the type context.In particular, the
rustc_middle::ty::structural_impls
module (and a few others) utilised therustc_middle::macros::TrivialTypeTraversalImpls
macro-by-example to define traversable trait implementations for many such "atomic" types. Making such implementations generic over the interner where those types are foreign torustc_middle
requires those implementations to move into either the type library or the crate that defines the type. In this PR I have opted for the latter approach, which creates some new dependencies on the type library (for access to the traits); the former would either require the type library to further depend on other parts of the compiler (undesirable, I think?) or for those types themselves to move into it (as previously happened for some basic types and is potentially desirable for further types in a future PR).Because these implementations are all rather trivial, they are provided by (modified versions of) the existing
TypeFoldable
andTypeVisitable
derive macros. These macros now produce implementations that either specify theTyCtxt
interner or are generic over the interner depending on whether the type for which they are derived is defined with a'tcx
lifetime parameter or not.r? @oli-obk