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
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2433,7 +2433,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
body.type_outlives,
builder.freeze(),
);
self.infcx.insert_placeholder_assumptions(u, Some(assumptions));
self.infcx.insert_placeholder_assumptions(u, assumptions);
self.check_test_binder_body(body.value);
let solver_region_constraint = self.infcx.get_solver_region_constraint();
let constraint = ty::region_constraint::eagerly_handle_placeholders_in_universe(
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_infer/src/infer/context.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//! Definition of `InferCtxtLike` from the librarified type layer.
use std::range::RangeInclusive;

use rustc_data_structures::sso::SsoHashMap;
use rustc_hir::def_id::DefId;
use rustc_middle::traits::ObligationCause;
Expand Down Expand Up @@ -49,15 +51,15 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
fn insert_placeholder_assumptions(
&self,
u: ty::UniverseIndex,
assumptions: Option<rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>>,
assumptions: rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>,
) {
self.insert_placeholder_assumptions(u, assumptions);
}

fn get_placeholder_assumptions(
&self,
u: ty::UniverseIndex,
) -> Option<rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>> {
) -> rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>> {
self.get_placeholder_assumptions(u)
}

Expand All @@ -67,6 +69,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
self.get_solver_region_constraint().without_spans()
}

fn has_placeholder_assumptions(&self, range: RangeInclusive<ty::UniverseIndex>) -> bool {
self.has_placeholder_assumptions(range)
}

fn overwrite_solver_region_constraint(
&self,
constraint: rustc_type_ir::region_constraint::RegionConstraint<TyCtxt<'tcx>>,
Expand Down Expand Up @@ -189,7 +195,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
let u = self.universe();
self.placeholder_assumptions_for_next_solver
.borrow_mut()
.insert(u, Some(rustc_type_ir::region_constraint::Assumptions::empty()));
.insert(u, rustc_type_ir::region_constraint::Assumptions::empty());
f(value)
})
}
Expand Down
42 changes: 23 additions & 19 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::cell::{Cell, RefCell};
use std::fmt;
use std::range::RangeInclusive;

pub use at::DefineOpaqueTypes;
use free_regions::RegionRelations;
Expand Down Expand Up @@ -335,10 +336,7 @@ pub struct InferCtxt<'tcx> {
// FIXME(-Zassumptions-on-binders): This and `universe` should probably be
// in `InferCtxtInner` so they can participate in rollbacks and whatnot
placeholder_assumptions_for_next_solver: RefCell<
FxIndexMap<
ty::UniverseIndex,
Option<rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>>,
>,
FxIndexMap<ty::UniverseIndex, rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>>,
>,

next_trait_solver: bool,
Expand Down Expand Up @@ -1579,28 +1577,34 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn insert_placeholder_assumptions(
&self,
u: ty::UniverseIndex,
assumptions: Option<rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>>,
assumptions: rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>,
) {
if let Some(assumptions) = &assumptions {
assert!(
!assumptions.type_outlives.has_escaping_bound_vars(),
"assumptions has escaping bound vars, which is indicative of a bug in how assumptions are handled: {:?}",
assumptions.type_outlives
);
assert!(
assumptions.region_outlives.base_edges().all(|r| !r.has_escaping_bound_vars()),
"assumptions has escaping bound vars, which is indicative of a bug in how assumptions are handled: {:?}",
assumptions.region_outlives
);
}
assert!(
!assumptions.type_outlives.has_escaping_bound_vars(),
"assumptions has escaping bound vars, which is indicative of a bug in how assumptions are handled: {:?}",
assumptions.type_outlives
);
assert!(
assumptions.region_outlives.base_edges().all(|r| !r.has_escaping_bound_vars()),
"assumptions has escaping bound vars, which is indicative of a bug in how assumptions are handled: {:?}",
assumptions.region_outlives
);
self.placeholder_assumptions_for_next_solver.borrow_mut().insert(u, assumptions);
}

pub fn get_placeholder_assumptions(
&self,
u: ty::UniverseIndex,
) -> Option<rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>> {
self.placeholder_assumptions_for_next_solver.borrow().get(&u).unwrap().as_ref().cloned()
) -> rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>> {
self.placeholder_assumptions_for_next_solver.borrow().get(&u).unwrap().clone()
}

pub fn has_placeholder_assumptions(&self, range: RangeInclusive<ty::UniverseIndex>) -> bool {
let assumptions = self.placeholder_assumptions_for_next_solver.borrow();
// Walk around that `Step` trait is nightly only.
(range.start.index()..=range.last.index())
.map(ty::UniverseIndex::from_usize)
.all(|u| assumptions.get(&u).is_some())
}

pub fn get_solver_region_constraint(&self) -> SolverRegionConstraint<'tcx> {
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_infer/src/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,6 @@ impl<'tcx> InferCtxt<'tcx> {
&assumptions,
);
debug!(?constraint);
let constraint = region_constraint::propagate_ambiguity(constraint);
debug!(?constraint);

// FIXME(-Zassumptions-on-binders): actually implement OR as an OR
for c in constraint.and_constraint.0.into_iter().chain(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_next_trait_solver/src/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ where
// recreated universes here.
delegate.insert_placeholder_assumptions(
new_universe,
Some(rustc_type_ir::region_constraint::Assumptions::empty()),
rustc_type_ir::region_constraint::Assumptions::empty(),
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_next_trait_solver/src/placeholder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ where
// context to compute placeholder assumptions for the binders it enters.
infcx.insert_placeholder_assumptions(
*new,
Some(rustc_type_ir::region_constraint::Assumptions::empty()),
rustc_type_ir::region_constraint::Assumptions::empty(),
);
}
}
Expand Down
24 changes: 13 additions & 11 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::ops::ControlFlow;
use rustc_macros::StableHash;
use rustc_type_ir::data_structures::HashSet;
use rustc_type_ir::inherent::*;
use rustc_type_ir::region_constraint::{self, RegionConstraint};
use rustc_type_ir::region_constraint::RegionConstraint;
use rustc_type_ir::relate::Relate;
use rustc_type_ir::relate::solver_relating::RelateExt;
use rustc_type_ir::search_graph::{
Expand Down Expand Up @@ -1292,13 +1292,19 @@ where
f: impl FnOnce(&mut Self, T) -> U,
) -> U {
self.delegate.enter_forall_without_assumptions(value, |value| {
// Invariant: we shouldn't insert empty assumptions if assumptions computation fails.
// When handling placeholder constraints, we rely on vacancies to force ambiguity.
let u = self.delegate.universe();
let assumptions = if self.cx().assumptions_on_binders() {
self.region_assumptions_for_placeholders_in_universe(value.clone(), u, param_env)
} else {
None
};
self.delegate.insert_placeholder_assumptions(u, assumptions);
if self.cx().assumptions_on_binders()
&& let Some(assumptions) = self.region_assumptions_for_placeholders_in_universe(
value.clone(),
u,
param_env,
)
{
self.delegate.insert_placeholder_assumptions(u, assumptions);
}

f(self, value)
})
}
Expand Down Expand Up @@ -1672,10 +1678,6 @@ where
let region_constraints = if self.cx().assumptions_on_binders() {
ExternalRegionConstraints::NextGen(if let Certainty::Yes = certainty {
let constraint = self.delegate.get_solver_region_constraint();
debug_assert_eq!(
constraint,
region_constraint::propagate_ambiguity(constraint.clone())
);
constraint
} else {
RegionConstraint::new_true()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use rustc_type_ir::outlives::{Component, push_outlives_components};
use rustc_type_ir::region_constraint::TransitiveRelationBuilder;
use rustc_type_ir::region_constraint::{
And, Assumptions, LeafRegionConstraint, Or, eagerly_handle_placeholders_in_universe,
propagate_ambiguity,
};
use rustc_type_ir::{
AliasTy, Binder, ClauseKind, Const, InferCtxtLike, Interner, Region, TypeVisitable,
Expand Down Expand Up @@ -115,17 +114,27 @@ where
pub(super) fn eagerly_handle_placeholders(&mut self) -> Result<Certainty, NoSolution> {
let constraint = self.delegate.get_solver_region_constraint();

let smallest_universe = self.max_input_universe.index();
let largest_universe = self.delegate.universe().index();
debug!(?smallest_universe, largest_universe);
let smallest_universe = self.max_input_universe;
let largest_universe = self.delegate.universe();
debug!("smallest_universe={smallest_universe:#?}, largest_universe={largest_universe:#?}");

let constraint = ((smallest_universe + 1)..=largest_universe)
.map(|u| UniverseIndex::from_usize(u))
// We rely on placeholder assumptions to evaluate region constraints with placeholders.
// But we can fail to compute assumptions due to unresolved type variables. In that case,
// we conservatively bail with ambiguity.
if !self

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a comment explaining why we use ambiguity here

.delegate
.has_placeholder_assumptions(((smallest_universe + 1)..=largest_universe).into())
{
return Ok(Certainty::AMBIGUOUS);
}

// Walk around that `Step` trait is nightly only.
let constraint = ((smallest_universe.index() + 1)..=largest_universe.index())
.map(UniverseIndex::from_usize)
.rev()
.fold(constraint, |constraint, u| {
eagerly_handle_placeholders_in_universe(&**self.delegate, constraint, u)
});
let constraint = propagate_ambiguity(constraint);

debug!("final constraint={:?}", constraint);
self.delegate.overwrite_solver_region_constraint(constraint.clone(), self.origin_span);
Expand Down Expand Up @@ -164,7 +173,9 @@ where
Or::new_leaf(PlaceholderTyOutlives(Ty::new_placeholder(self.cx(), *p), r, ()))
}
Alias(_, alias) => self.destructure_alias_outlives(*alias, r),
UnresolvedInferenceVariable(_) => Or::new_ambig(()),
UnresolvedInferenceVariable(_) => {
panic!("Shouldn't destructure type outlives when ty vars exist")
}
Param(_) => panic!("Params should have been canonicalized to placeholders"),
EscapingAlias(components) => self.destructure_components(components, r),
}
Expand Down
21 changes: 12 additions & 9 deletions compiler/rustc_next_trait_solver/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,6 @@ where
let ty::OutlivesClause(ty, lt) = goal.predicate;
let ty = self.normalize(GoalSource::Misc, goal.param_env, ty::Unnormalized::new_wip(ty))?;

if self.cx().assumptions_on_binders() {
use rustc_type_ir::region_constraint::RegionConstraint;

let constraint = self.destructure_type_outlives(ty, lt);
self.register_solver_region_constraint(RegionConstraint::new_from_or(constraint));
} else {
self.register_ty_outlives(ty, lt);
}

// The normalized type can still contain non-rigid higher ranked aliases if their
// normalization ends up with ambiguity. Or we have non-rigid aliases inside rigid ones.
// Infer vars may be resolved to types/consts containing non-rigid aliases later.
Expand All @@ -109,6 +100,18 @@ where
if ty.has_non_region_infer() || ty.has_non_rigid_aliases() {
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
} else {
// We drop region constraints in ambiguous response so there's no need to add them in
// the ambiguous branch. Also this guarantees we don't have ty vars when destructuring
// type outlives.
if self.cx().assumptions_on_binders() {
use rustc_type_ir::region_constraint::RegionConstraint;

let constraint = self.destructure_type_outlives(ty, lt);
self.register_solver_region_constraint(RegionConstraint::new_from_or(constraint));
} else {
self.register_ty_outlives(ty, lt);
}

self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
}
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_type_ir/src/infer_ctxt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::fmt;
use std::hash::{Hash, Hasher};
use std::range::RangeInclusive;

use derive_where::derive_where;
#[cfg(feature = "nightly")]
Expand Down Expand Up @@ -407,12 +408,13 @@ pub trait InferCtxtLike: Sized {
fn insert_placeholder_assumptions(
&self,
u: ty::UniverseIndex,
assumptions: Option<crate::region_constraint::Assumptions<Self::Interner>>,
assumptions: crate::region_constraint::Assumptions<Self::Interner>,
);
fn get_placeholder_assumptions(
&self,
u: ty::UniverseIndex,
) -> Option<crate::region_constraint::Assumptions<Self::Interner>>;
) -> crate::region_constraint::Assumptions<Self::Interner>;
fn has_placeholder_assumptions(&self, range: RangeInclusive<ty::UniverseIndex>) -> bool;
fn get_solver_region_constraint(
&self,
) -> crate::region_constraint::RegionConstraint<Self::Interner>;
Expand Down
Loading
Loading