Skip to content

Region inference: split results from RegionInferenceContext#151688

Open
amandasystems wants to merge 1 commit intorust-lang:mainfrom
amandasystems:split-region-inference
Open

Region inference: split results from RegionInferenceContext#151688
amandasystems wants to merge 1 commit intorust-lang:mainfrom
amandasystems:split-region-inference

Conversation

@amandasystems
Copy link
Contributor

@amandasystems amandasystems commented Jan 26, 2026

What?

This PR turns RegionInferenceContext into a builder that produces the inferred region values, InferredRegions. The resulting struct implements the public API of RegionInferenceContext and replaces it in consumers.rs. RegionInferenceContext::solve() now consumes (moves) the inference context. It is completely private to region inference.

Why?

  • RegionInferenceContext has become a huge dump for various values people want to access.
  • region_infer itself is a very large file that's difficult to find your way around.
  • Polonius wants to skip as much of region inference as possible, since most of it is redundant. This makes that possible
  • No method now need warnings about being called after region inference or else they'll panic
  • RegionInferenceContext now takes almost all of its fields by reference
  • We can probably drop at least some stuff earlier
  • Data dependencies during region inference are now made more explicit

Knock-on effects

  • Region constraint (blame) search is now independent of a RegionInferenceContext
  • Less data is retained after region inference. This may or may not lead to minor improvements in memory use.
  • RegionInferenceContext now almost exclusively contains references to values, as opposed to owning them. This addresses most of fn compute_closure_requirements_modulo_opaques shouldn't clone all its inputs #146079
  • This reduces the coupling between region inference and Polonius-next, making it possible to skip region inference if it is not needed to check universal regions or type tests.
  • region_infer gains two child modules and becomes a lot less of a behemoth.

Detailed overview of changes

  • new modules: region_infer::constraint_search and region_infer::universal_regions.
  • handle_placeholders now consumes less input and does constraint rewriting via mutable references
  • consumers.rs now has a InferenceResults instead of a RegionInferenceContext
  • The public methods eval_{equal, outlives} are moved to InferredRegions
  • Constraint (blame) search, MIR dumping, graphviz rendering, and checking universal regions now all get their own builder-style structs, and the methods for their respective tasks are moved onto them
  • The option for region inference results in ConsumerOptions is now called InferredRegions
  • calculate_borrows_out_of_scope_at_location of course now takes InferredRegions
  • LivenessValues for free regions is now initialised as live at all points along with the constraint rewriting during placeholder handling, as opposed to during construction of RegionInferenceContext
  • Some trace logging, especially during constraint search, is lost since the data required to print the logs was only necessary to print the logs and never used otherwise.

r? @lcnr

Closes #146079.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 26, 2026
@rust-log-analyzer

This comment has been minimized.

@amandasystems amandasystems force-pushed the split-region-inference branch from 6befd69 to 13a57f6 Compare January 26, 2026 14:50
@rust-log-analyzer

This comment has been minimized.

@amandasystems amandasystems force-pushed the split-region-inference branch from 13a57f6 to 00e8121 Compare January 26, 2026 16:12
@amandasystems amandasystems force-pushed the split-region-inference branch from 00e8121 to 454f98a Compare January 28, 2026 22:21
@rustbot

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@amandasystems amandasystems force-pushed the split-region-inference branch from 4c01f95 to 174023c Compare February 6, 2026 14:58
@rustbot

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-bors

This comment has been minimized.

liveness: &LivenessValues,
pass_where: PassWhere,
out: &mut dyn io::Write,
) -> io::Result<()> {
Copy link
Contributor

Choose a reason for hiding this comment

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

pls use a consistent function param ordering between the functions here :<

let (definitions, _has_placeholders) = region_definitions(
infcx,
universal_regions,
&mut constraints.liveness_constraints.clone(),
Copy link
Contributor

Choose a reason for hiding this comment

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

this is... very odd. You give a mutable reference to a clone?

please move the cloned thing into a let binding first

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a quick hack workaround, I think we should talk about how to not have to do that, where to put region_definitions(), and whether the liveness constarints stuff is necessary in sync because it's pretty much the same thing.

outlives_constraints: &'a OutlivesConstraintSet<'tcx>,
mut w: &mut dyn Write,
) -> io::Result<()> {
dot::render(&RawConstraints { tcx, region_definitions, outlives_constraints }, &mut w)
Copy link
Contributor

Choose a reason for hiding this comment

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

why reference RawConstraints. That type should be Copy

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's because dot::render() takes its arguments by reference (and it wasn't written by me).

dot::render(&SccConstraints { tcx, region_definitions, constraint_sccs, nodes_per_scc }, &mut w)
}

struct RawConstraints<'a, 'tcx> {
Copy link
Contributor

Choose a reason for hiding this comment

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

make this copy and take it by value

nodes_per_scc: IndexVec<ConstraintSccIndex, Vec<RegionVid>>,
region_definitions: &'a IndexVec<RegionVid, RegionDefinition<'tcx>>,
constraint_sccs: &'a ConstraintSccs,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

same here

outlives_requirements.as_mut(),
&mut errors_buffer,
type_tests,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

hmm, I would prefer check_type_tests to stay on the region inference context 🤔

they are a part of region inference to me

Copy link
Contributor

Choose a reason for hiding this comment

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

or like, the RegionInferenceCtxt should either not exist at all anymore, or still be used for the region computations 🤔 maybe chat about it in sync

if let NllRegionVariableOrigin::FreeRegion = origin {
// Add all nodes in the CFG to liveness constraints for free regions
liveness_constraints.add_all_points(rvid);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

this is a functional change? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It should not be, this always happens during region inference, I just moved it slightly earlier.

Copy link
Contributor

@lcnr lcnr left a comment

Choose a reason for hiding this comment

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

scc_values: InferredRegions feels wrong. Maybe just computed_regions: ComputedRegions, regions: InferredRegions

region_definitions why mutable liveness constraints

MirDumper::dump_mir why is scc_values an fn param instead of a field?

View changes since this review

Comment on lines +102 to +103
// These clones can more or less be avoided,
// since they are probably idempotent.
Copy link
Contributor

Choose a reason for hiding this comment

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

what exactly does this comment mean? It's confusing to me

Copy link
Contributor Author

@amandasystems amandasystems Feb 23, 2026

Choose a reason for hiding this comment

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

It's a grammar error; what I meant was that the clones make the operations local since it operates on cloned values as opposed to shared ones, but the operations being performed are probably idempotent so doing them twice (in case of shared values) is likely fine. In other words, just dropping the clones will probably do the right thing.

@lcnr
Copy link
Contributor

lcnr commented Feb 12, 2026

Can you rebase, I will then do a perf run and locally look at the docs after this PR as that should make it clearer how the API has changed

@amandasystems amandasystems force-pushed the split-region-inference branch from aae5ccc to 6e2ad5a Compare March 3, 2026 15:44
@rustbot
Copy link
Collaborator

rustbot commented Mar 3, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@amandasystems
Copy link
Contributor Author

Can you rebase, I will then do a perf run and locally look at the docs after this PR as that should make it clearer how the API has changed

Phew! That was quite a rebase! Fixed it now, but I had to squash. I suspect we will want to land this in stages anyway.

@rust-log-analyzer

This comment has been minimized.

This ensures all of region inference is immutable, and makes every
operation that requires region inference to have been executed to run
explicitly require the results.
@amandasystems amandasystems force-pushed the split-region-inference branch from 6e2ad5a to 447cc9d Compare March 4, 2026 21:33
@lcnr
Copy link
Contributor

lcnr commented Mar 9, 2026

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 9, 2026
rust-bors bot pushed a commit that referenced this pull request Mar 9, 2026
Region inference: split results from RegionInferenceContext
@rust-bors
Copy link
Contributor

rust-bors bot commented Mar 9, 2026

☀️ Try build successful (CI)
Build commit: 1ee78dc (1ee78dc33b57da0d3c9e4cb23d402532bafd397b, parent: 655a7d20fefe23757ca9ecbbea01e4fe80208aaf)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (1ee78dc): comparison URL.

Overall result: ❌ regressions - please read the text below

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please do so in sufficient writing along with @rustbot label: +perf-regression-triaged. If not, please fix the regressions and do another perf run. If its results are neutral or positive, the label will be automatically removed.

@bors rollup=never
@rustbot label: -S-waiting-on-perf +perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
0.3% [0.1%, 0.7%] 11
Regressions ❌
(secondary)
0.3% [0.2%, 0.5%] 15
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.3% [0.1%, 0.7%] 11

Max RSS (memory usage)

Results (secondary 2.5%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
2.5% [2.5%, 2.5%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Cycles

Results (secondary 2.2%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
2.2% [2.2%, 2.2%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 479.555s -> 479.91s (0.07%)
Artifact size: 395.03 MiB -> 394.99 MiB (-0.01%)

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

perf-regression Performance regression. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fn compute_closure_requirements_modulo_opaques shouldn't clone all its inputs

5 participants