Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions compiler/rustc_borrowck/src/handle_placeholders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,16 +246,8 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
mut outlives_constraints,
universe_causes,
type_tests,
solver_constraints,
} = constraints;

// These have already been destructured into `outlives_constraints` at the
// end of MIR type checking.
assert!(
solver_constraints.is_true(),
"solver region constraints not lowered to NLL = {solver_constraints:#?}",
);

let fr_static = universal_regions.fr_static;
let compute_sccs =
|constraints: &OutlivesConstraintSet<'tcx>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {

#[instrument(skip(self), level = "debug")]
pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
let QueryRegionConstraints { constraints, assumptions, solver_constraints } =
query_constraints;
let QueryRegionConstraints { constraints, assumptions } = query_constraints;
let assumptions =
elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied());

Expand All @@ -77,9 +76,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
self.convert(predicate, category, &assumptions);
});
}

self.constraints
.register_solver_constraint(solver_constraints.clone().with_spans(self.span));
}

/// Given an instance of the closure type, this method instantiates the "extra" requirements
Expand Down
30 changes: 0 additions & 30 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::{
BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin,
SolverRegionConstraint,
};
use rustc_infer::traits::{Obligation, ObligationCause, PredicateObligations};
use rustc_middle::bug;
Expand Down Expand Up @@ -114,7 +113,6 @@ pub(crate) fn type_check<'tcx>(
outlives_constraints: OutlivesConstraintSet::default(),
type_tests: Vec::default(),
universe_causes: FxIndexMap::default(),
solver_constraints: SolverRegionConstraint::new_true(),
};

let CreateResult {
Expand All @@ -136,13 +134,6 @@ pub(crate) fn type_check<'tcx>(
pre_assumptions.is_empty(),
"there should be no incoming region assumptions = {pre_assumptions:#?}",
);
// Solver region constraints from computing the implied bounds went through
// `ConstraintConversion` and are already stored in `constraints`.
let pre_solver_constraints = infcx.take_solver_region_constraints();
assert!(
pre_solver_constraints.is_true(),
"there should be no incoming solver region constraints = {pre_solver_constraints:#?}",
);
}

debug!(?normalized_inputs_and_output);
Expand Down Expand Up @@ -183,10 +174,6 @@ pub(crate) fn type_check<'tcx>(
let polonius_context = typeck.polonius_context;

if infcx.tcx.assumptions_on_binders() {
let solver_constraints = mem::replace(
&mut typeck.constraints.solver_constraints,
SolverRegionConstraint::new_true(),
);
let mut converter = constraint_conversion::ConstraintConversion::new(
typeck.infcx,
typeck.universal_regions,
Expand All @@ -198,7 +185,6 @@ pub(crate) fn type_check<'tcx>(
typeck.constraints,
);
typeck.infcx.destructure_solver_region_constraints_for_borrowck(
solver_constraints,
&mut converter,
typeck.known_type_outlives_obligations,
typeck.region_bound_pairs,
Expand Down Expand Up @@ -308,25 +294,9 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
pub(crate) universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,

pub(crate) type_tests: Vec<TypeTest<'tcx>>,

/// The region constraints emitted by the next solver under
/// `-Zassumptions-on-binders`. Unlike the constraints above these are not yet
/// lowered to NLL, we destructure them into `outlives_constraints` at the end
/// of MIR type checking.
pub(crate) solver_constraints: SolverRegionConstraint<'tcx>,
}

impl<'tcx> MirTypeckRegionConstraints<'tcx> {
/// Adds `constraint` to the constraints we've accumulated so far.
pub(crate) fn register_solver_constraint(&mut self, constraint: SolverRegionConstraint<'tcx>) {
// FIXME(-Zassumptions-on-binders): This is pretty bad for perf, we rebuild the
// entire constraint every time instead of updating it incrementally.
self.solver_constraints = SolverRegionConstraint::build_and(
constraint,
mem::replace(&mut self.solver_constraints, SolverRegionConstraint::new_true()),
);
}

/// Creates a `Region` for a given `PlaceholderRegion`, or returns the
/// region that corresponds to a previously created one.
pub(crate) fn placeholder_region(
Expand Down
52 changes: 20 additions & 32 deletions compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,11 @@ impl<'tcx> InferCtxt<'tcx> {
let region_obligations = self.take_registered_region_obligations();
let region_assumptions = self.take_registered_region_assumptions();
debug!(?region_obligations);
let solver_constraints = self.take_solver_region_constraints();
let region_constraints = self.with_region_constraints(|region_constraints| {
make_query_region_constraints(
region_obligations,
region_constraints,
region_assumptions,
solver_constraints,
)
});
debug!(?region_constraints);
Expand Down Expand Up @@ -197,10 +195,9 @@ impl<'tcx> InferCtxt<'tcx> {
let InferOk { value: result_args, obligations } =
self.query_response_instantiation(cause, param_env, original_values, query_response)?;

let QueryRegionConstraints { constraints, assumptions, solver_constraints } =
&query_response.value.region_constraints;

for QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in constraints {
for QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in
&query_response.value.region_constraints.constraints
{
let constraint = instantiate_value(self.tcx, &result_args, *constraint);
match constraint {
ty::RegionConstraint::Outlives(clause) => {
Expand All @@ -212,15 +209,11 @@ impl<'tcx> InferCtxt<'tcx> {
}
}

for assumption in assumptions {
for assumption in &query_response.value.region_constraints.assumptions {
let assumption = instantiate_value(self.tcx, &result_args, *assumption);
self.register_region_assumption(assumption);
}

let solver_constraints =
instantiate_value(self.tcx, &result_args, solver_constraints.clone());
self.register_solver_region_constraint(solver_constraints.with_spans(cause.span));

let user_result: R =
query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());

Expand Down Expand Up @@ -332,31 +325,27 @@ impl<'tcx> InferCtxt<'tcx> {
}
}

let QueryRegionConstraints { constraints, assumptions, solver_constraints } =
&query_response.value.region_constraints;

// ...also include the other query region constraints from the query.
output_query_region_constraints.constraints.extend(constraints.iter().filter_map(|&r_c| {
let r_c = instantiate_value(self.tcx, &result_args, r_c);
output_query_region_constraints.constraints.extend(
query_response.value.region_constraints.constraints.iter().filter_map(|&r_c| {
let r_c = instantiate_value(self.tcx, &result_args, r_c);

// Screen out `'a: 'a` or `'a == 'a` cases.
if r_c.constraint.is_trivial() { None } else { Some(r_c) }
}));
// Screen out `'a: 'a` or `'a == 'a` cases.
if r_c.constraint.is_trivial() { None } else { Some(r_c) }
}),
);

// FIXME(higher_ranked_auto): Optimize this to instantiate all assumptions
// at once, rather than calling `instantiate_value` repeatedly which may
// create more universes.
output_query_region_constraints
.assumptions
.extend(assumptions.iter().map(|&r_c| instantiate_value(self.tcx, &result_args, r_c)));

let solver_constraints =
instantiate_value(self.tcx, &result_args, solver_constraints.clone());
output_query_region_constraints.solver_constraints =
ty::region_constraint::RegionConstraint::build_and(
std::mem::take(&mut output_query_region_constraints.solver_constraints),
solver_constraints,
);
output_query_region_constraints.assumptions.extend(
query_response
.value
.region_constraints
.assumptions
.iter()
.map(|&r_c| instantiate_value(self.tcx, &result_args, r_c)),
);

let user_result: R =
query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
Expand Down Expand Up @@ -630,7 +619,6 @@ pub fn make_query_region_constraints<'tcx>(
outlives_obligations: Vec<TypeOutlivesConstraint<'tcx>>,
region_constraints: &RegionConstraintData<'tcx>,
assumptions: Vec<ty::ArgOutlivesClause<'tcx>>,
solver_constraints: ty::region_constraint::RegionConstraint<TyCtxt<'tcx>>,
) -> QueryRegionConstraints<'tcx> {
let RegionConstraintData { constraints, verifys } = region_constraints;

Expand Down Expand Up @@ -675,5 +663,5 @@ pub fn make_query_region_constraints<'tcx>(
))
.collect();

QueryRegionConstraints { constraints, assumptions, solver_constraints }
QueryRegionConstraints { constraints, assumptions }
}
11 changes: 3 additions & 8 deletions compiler/rustc_infer/src/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,16 +251,11 @@ impl<'tcx> InferCtxt<'tcx> {
region_outlives.freeze(),
ty::UniverseIndex::ROOT,
);
let constraint = self.inner.borrow().solver_region_constraint_storage.get_constraint();
self.destructure_solver_region_constraints(constraint, assumptions, self);
self.destructure_solver_region_constraints(assumptions, self);
}

/// Unlike regionck, borrowck doesn't keep these constraints in the `InferCtxt`.
/// It stores them in `MirTypeckRegionConstraints` alongside its other region
/// constraints, so it hands us the constraint to destructure.
pub fn destructure_solver_region_constraints_for_borrowck(
&self,
constraint: SolverRegionConstraint<'tcx>,
// this is always ConstraintConversion but lol
conversion: impl TypeOutlivesDelegate<'tcx>,
known_type_outlives: &[PolyTypeOutlivesClause<'tcx>],
Expand All @@ -273,19 +268,19 @@ impl<'tcx> InferCtxt<'tcx> {
region_outlives.maybe_map(|r| Some(Region::new_var(self.tcx, r))).unwrap(),
ty::UniverseIndex::ROOT,
);
self.destructure_solver_region_constraints(constraint, assumptions, conversion);
self.destructure_solver_region_constraints(assumptions, conversion);
}

#[instrument(level = "debug", skip(self, conversion))]
pub fn destructure_solver_region_constraints(
&self,
constraint: SolverRegionConstraint<'tcx>,
assumptions: rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>,
mut conversion: impl TypeOutlivesDelegate<'tcx>,
) {
assert!(self.tcx.assumptions_on_binders());
assert!(self.next_trait_solver());

let constraint = self.inner.borrow().solver_region_constraint_storage.get_constraint();
debug!(?constraint);
let constraint = region_constraint::destructure_type_outlives_constraints_in_root(
self,
Expand Down
19 changes: 2 additions & 17 deletions compiler/rustc_infer/src/infer/solver_region_constraints.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
use rustc_type_ir::region_constraint::RegionConstraint;
use tracing::instrument;

use super::InferCtxt;

pub type SolverRegionConstraint<'tcx> = RegionConstraint<TyCtxt<'tcx>, Span>;
pub type SolverRegionConstraint<'tcx> =
rustc_type_ir::region_constraint::RegionConstraint<TyCtxt<'tcx>, Span>;

#[derive(Clone, Debug)]
pub(crate) struct SolverRegionConstraintStorage<'tcx>(SolverRegionConstraint<'tcx>);
Expand All @@ -19,24 +17,11 @@ impl<'tcx> SolverRegionConstraintStorage<'tcx> {
self.0.clone()
}

pub(crate) fn take(&mut self) -> SolverRegionConstraint<'tcx> {
core::mem::replace(&mut self.0, SolverRegionConstraint::new_true())
}

#[instrument(level = "debug", skip(self))]
pub(crate) fn overwrite(&mut self, constraint: SolverRegionConstraint<'tcx>) {
self.0 = constraint;
}
}

impl<'tcx> InferCtxt<'tcx> {
/// Trait queries just want to pass back the solver region constraints "as is",
/// mirroring `take_registered_region_obligations`.
pub fn take_solver_region_constraints(&self) -> RegionConstraint<TyCtxt<'tcx>> {
assert!(!self.in_snapshot(), "cannot take solver region constraints in a snapshot");
self.inner.borrow_mut().solver_region_constraint_storage.take().without_spans()
}
}

#[cfg(test)]
mod tests;
22 changes: 0 additions & 22 deletions compiler/rustc_infer/src/infer/solver_region_constraints/tests.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,7 @@
use rustc_middle::infer::canonical::QueryRegionConstraints;
use rustc_middle::ty::TyCtxt;
use rustc_span::{BytePos, Span};
use rustc_type_ir::region_constraint::{And, LeafRegionConstraint, Or};

use super::{SolverRegionConstraint, SolverRegionConstraintStorage};

#[test]
fn true_constraint_keeps_query_response_empty() {
// Mirrors `register_solver_region_constraint`, which registers unconditionally:
// anding a trivially true constraint into an empty store has to leave the store
// trivially true, as the resulting query response would otherwise no longer be
// empty. This relies on `And`/`Or` being kept in canonical form.
let mut storage = SolverRegionConstraintStorage::<'static>::new();
storage.overwrite(SolverRegionConstraint::build_and(
SolverRegionConstraint::new_true(),
storage.get_constraint(),
));

let constraints = QueryRegionConstraints {
solver_constraints: storage.get_constraint().without_spans(),
..Default::default()
};
assert!(constraints.is_empty());
}

#[test]
fn canonicalization_preserves_only_one_ambiguity() {
let first = Span::with_root_ctxt(BytePos(1), BytePos(2));
Expand Down
29 changes: 3 additions & 26 deletions compiler/rustc_middle/src/infer/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,13 @@ pub struct QueryResponse<'tcx, R> {
pub value: R,
}

#[derive(Clone, Debug, Default, PartialEq, Hash)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[derive(StableHash, TypeFoldable, TypeVisitable)]
pub struct QueryRegionConstraints<'tcx> {
pub constraints: Vec<QueryRegionConstraint<'tcx>>,
pub assumptions: Vec<ty::ArgOutlivesClause<'tcx>>,
/// Region constraints emitted by the next solver under
/// `-Zassumptions-on-binders`.
///
/// These stay unspanned while passing through a canonical query. The type-op
/// caller attaches its origin span when consuming the response.
pub solver_constraints: ir::region_constraint::RegionConstraint<TyCtxt<'tcx>>,
}

impl Eq for QueryRegionConstraints<'_> {}

impl QueryRegionConstraints<'_> {
/// Represents an empty (trivially true) set of region constraints.
///
Expand All @@ -99,23 +91,8 @@ impl QueryRegionConstraints<'_> {
/// discharge a requirement from another query, which is a potential problem if we did throw
/// away these assumptions because there were no constraints.
pub fn is_empty(&self) -> bool {
let QueryRegionConstraints { constraints, assumptions, solver_constraints } = self;
constraints.is_empty() && assumptions.is_empty() && solver_constraints.is_true()
}

pub fn extend(&mut self, other: &Self) {
let QueryRegionConstraints { constraints, assumptions, solver_constraints } = self;
let QueryRegionConstraints {
constraints: other_constraints,
assumptions: other_assumptions,
solver_constraints: other_solver_constraints,
} = other;
constraints.extend(other_constraints.iter().cloned());
assumptions.extend(other_assumptions.iter().cloned());
*solver_constraints = ir::region_constraint::RegionConstraint::build_and(
std::mem::take(solver_constraints),
other_solver_constraints.clone(),
);
let QueryRegionConstraints { constraints, assumptions } = self;
constraints.is_empty() && assumptions.is_empty()
}
}

Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_trait_selection/src/solve/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,11 +374,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
region_obligations,
region_constraints,
region_assumptions,
// We're only called with `-Zassumptions-on-binders` disabled, in which
// case the solver never emits new-style region constraints. With it
// enabled the solver instead returns `ExternalRegionConstraints::NextGen`,
// reading the constraint straight out of the `InferCtxt`.
Default::default(),
)
});

Expand Down
Loading
Loading