Skip to content
Open
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
11 changes: 3 additions & 8 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,14 +478,9 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> {
let errci = ErrorConstraintInfo { fr, outlived_fr, category, span };

let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
(ConstraintCategory::SolverRegionConstraint(span), _, _) => {
let mut d = self.dcx().struct_span_err(
span,
"unsatisfied lifetime constraint from -Zassumptions-on-binders :3",
);
d.note("meoow :c");
d
}
(ConstraintCategory::SolverRegionConstraint(span), _, _) => self
.dcx()
.struct_span_err(span, "higher-ranked lifetime bound could not be satisfied"),
(ConstraintCategory::Return(kind), true, false)
if self.regioncx.is_closure_fn_mut(fr) =>
{
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ pub(crate) fn type_check<'tcx>(
&mut converter,
typeck.known_type_outlives_obligations,
universal_region_relations.outlives.clone(),
infcx.tcx.def_span(infcx.root_def_id),
);
}

Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_infer/src/infer/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,21 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
fn get_solver_region_constraint(
&self,
) -> rustc_type_ir::region_constraint::RegionConstraint<TyCtxt<'tcx>> {
self.inner.borrow().solver_region_constraint_storage.get_constraint()
self.inner.borrow().solver_region_constraint_storage.get_unspanned_constraint()
}

fn overwrite_solver_region_constraint(
&self,
constraint: rustc_type_ir::region_constraint::RegionConstraint<TyCtxt<'tcx>>,
span: Span,
) {
let mut inner = self.inner.borrow_mut();
use rustc_data_structures::undo_log::UndoLogs;

use crate::infer::UndoLog;
let old_constraint = inner.solver_region_constraint_storage.get_constraint();
inner.undo_log.push(UndoLog::OverwriteSolverRegionConstraint { old_constraint });
inner.solver_region_constraint_storage.overwrite_solver_region_constraint(constraint);
inner.solver_region_constraint_storage.overwrite(constraint, span);
}

fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> {
Expand Down Expand Up @@ -367,13 +368,14 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
fn register_solver_region_constraint(
&self,
c: rustc_type_ir::region_constraint::RegionConstraint<TyCtxt<'tcx>>,
span: Span,
) {
let mut inner = self.inner.borrow_mut();
use rustc_data_structures::undo_log::UndoLogs;

use crate::infer::UndoLog;
inner.undo_log.push(UndoLog::PushSolverRegionConstraint);
inner.solver_region_constraint_storage.push(c);
inner.solver_region_constraint_storage.push(c, span);
}

fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>, span: Span) {
Expand Down
56 changes: 4 additions & 52 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,13 @@ pub mod region_constraints;
pub mod relate;
pub mod resolve;
pub(crate) mod snapshot;
mod solver_region_constraints;
mod type_variable;
mod unify_key;

pub(crate) use solver_region_constraints::SolverRegionConstraint;
use solver_region_constraints::SolverRegionConstraintStorage;

/// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper
/// around `PredicateObligations<'tcx>`, but it has one important property:
/// because `InferOk` is marked with `#[must_use]`, if you have a method
Expand Down Expand Up @@ -1844,55 +1848,3 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
}

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

#[derive(Clone, Debug)]
struct SolverRegionConstraintStorage<'tcx>(SolverRegionConstraint<'tcx>);

impl<'tcx> SolverRegionConstraintStorage<'tcx> {
fn new() -> Self {
SolverRegionConstraintStorage(SolverRegionConstraint::And(Box::new([])))
}

fn get_constraint(&self) -> SolverRegionConstraint<'tcx> {
self.0.clone()
}

fn pop(&mut self) -> Option<SolverRegionConstraint<'tcx>> {
match &mut self.0 {
SolverRegionConstraint::And(and) => {
let mut and = core::mem::take(and).into_iter().collect::<Vec<_>>();
let popped = and.pop()?;
self.0 = SolverRegionConstraint::And(and.into_boxed_slice());
Some(popped)
}
_ => unreachable!(),
}
}

#[instrument(level = "debug")]
fn push(&mut self, constraint: SolverRegionConstraint<'tcx>) {
match &mut self.0 {
SolverRegionConstraint::And(and) => {
let and = core::mem::take(and)
.into_iter()
.chain([constraint])
.collect::<Vec<_>>()
.into_boxed_slice();
self.0 = SolverRegionConstraint::And(and);
}
_ => unreachable!(),
}
}

#[instrument(level = "debug", skip(self))]
fn overwrite_solver_region_constraint(&mut self, constraint: SolverRegionConstraint<'tcx>) {
if !constraint.is_and() {
self.0 = SolverRegionConstraint::And(vec![constraint].into_boxed_slice())
} else {
self.0 = constraint;
}
}
}
32 changes: 15 additions & 17 deletions compiler/rustc_infer/src/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,12 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn destructure_solver_region_constraints_for_regionck(
&self,
outlives_env: &OutlivesEnvironment<'tcx>,
span: Span,
) {
let assumptions = rustc_type_ir::region_constraint::Assumptions::new(
outlives_env.known_type_outlives().into_iter().cloned().collect(),
outlives_env.free_region_map().relation.clone(),
);
self.destructure_solver_region_constraints(assumptions, self, span);
self.destructure_solver_region_constraints(assumptions, self);
}

pub fn destructure_solver_region_constraints_for_borrowck(
Expand All @@ -219,28 +218,23 @@ impl<'tcx> InferCtxt<'tcx> {
conversion: impl TypeOutlivesDelegate<'tcx>,
known_type_outlives: &[PolyTypeOutlivesPredicate<'tcx>],
region_outlives: TransitiveRelation<RegionVid>,
span: Span,
) {
let assumptions = rustc_type_ir::region_constraint::Assumptions::new(
known_type_outlives.into_iter().cloned().collect(),
region_outlives.maybe_map(|r| Some(Region::new_var(self.tcx, r))).unwrap(),
);
self.destructure_solver_region_constraints(assumptions, conversion, span);
self.destructure_solver_region_constraints(assumptions, conversion);
}

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

let origin = SubregionOrigin::SolverRegionConstraint(span);
let category = origin.to_constraint_category();

let constraint = self.inner.borrow().solver_region_constraint_storage.get_constraint();
debug!(?constraint);
let constraint =
Expand All @@ -258,16 +252,20 @@ impl<'tcx> InferCtxt<'tcx> {
use rustc_type_ir::region_constraint::RegionConstraint::*;

match c {
Ambiguity => {
self.dcx().err("unable to satisfy constraints involving placeholders due to unknown implied bounds");
Ambiguity(span) => {
self.dcx()
.struct_span_err(
span,
"unable to satisfy constraints involving placeholders due to unknown implied bounds",
)
.emit();
}
RegionOutlives(a, b) => {
RegionOutlives(a, b, span) => {
let origin = SubregionOrigin::SolverRegionConstraint(span);
let category = origin.to_constraint_category();
conversion.push_sub_region_constraint(
origin.clone(),
// we flip these because regionck is silly :>
b,
a,
category,
origin, // we flip these because regionck is silly :>
b, a, category,
);
}
// FIXME(-Zassumptions-on-binders): actually implement OR as an OR
Expand Down Expand Up @@ -295,7 +293,7 @@ impl<'tcx> InferCtxt<'tcx> {
assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");

if self.tcx.assumptions_on_binders() {
self.destructure_solver_region_constraints_for_regionck(outlives_env, span);
self.destructure_solver_region_constraints_for_regionck(outlives_env);
}

// Must loop since the process of normalizing may itself register region obligations.
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_infer/src/infer/snapshot/undo_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
);
}
UndoLog::OverwriteSolverRegionConstraint { old_constraint } => {
self.solver_region_constraint_storage
.overwrite_solver_region_constraint(old_constraint);
self.solver_region_constraint_storage.overwrite_spanned(old_constraint);
}
UndoLog::PushTypeOutlivesConstraint => {
let popped = self.region_obligations.pop();
Expand Down
73 changes: 73 additions & 0 deletions compiler/rustc_infer/src/infer/solver_region_constraints.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
use rustc_type_ir::region_constraint::{
RegionConstraint as UnspannedRegionConstraint, SpannedRegionConstraint,
};
use tracing::instrument;

pub(crate) type SolverRegionConstraint<'tcx> = SpannedRegionConstraint<TyCtxt<'tcx>>;

#[derive(Clone, Debug)]
pub(crate) struct SolverRegionConstraintStorage<'tcx>(SolverRegionConstraint<'tcx>);

impl<'tcx> SolverRegionConstraintStorage<'tcx> {
pub(crate) fn new() -> Self {
Self(SolverRegionConstraint::And(Box::new([])))
}

pub(crate) fn get_constraint(&self) -> SolverRegionConstraint<'tcx> {
self.0.clone()
}

pub(crate) fn get_unspanned_constraint(&self) -> UnspannedRegionConstraint<TyCtxt<'tcx>> {
self.0.clone().without_spans()
}

pub(crate) fn pop(&mut self) -> Option<SolverRegionConstraint<'tcx>> {
match &mut self.0 {
SolverRegionConstraint::And(and) => {
let mut and = core::mem::take(and).into_vec();
let popped = and.pop()?;
self.0 = SolverRegionConstraint::And(and.into_boxed_slice());
Some(popped)
}
_ => unreachable!(),
}
}

#[instrument(level = "debug")]
pub(crate) fn push(&mut self, constraint: UnspannedRegionConstraint<TyCtxt<'tcx>>, span: Span) {
let constraint = constraint.with_span(span);
match &mut self.0 {
SolverRegionConstraint::And(and) => {
let and = core::mem::take(and)
.into_iter()
.chain([constraint])
.collect::<Vec<_>>()
.into_boxed_slice();
self.0 = SolverRegionConstraint::And(and);
}
_ => unreachable!(),
}
}

#[instrument(level = "debug", skip(self))]
pub(crate) fn overwrite(
&mut self,
constraint: UnspannedRegionConstraint<TyCtxt<'tcx>>,
span: Span,
) {
self.overwrite_spanned(constraint.with_span(span));
}

pub(crate) fn overwrite_spanned(&mut self, constraint: SolverRegionConstraint<'tcx>) {
if matches!(constraint, SolverRegionConstraint::And(_)) {
self.0 = constraint;
} else {
self.0 = SolverRegionConstraint::And(vec![constraint].into_boxed_slice());
}
}
}

#[cfg(test)]
mod tests;
58 changes: 58 additions & 0 deletions compiler/rustc_infer/src/infer/solver_region_constraints/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use rustc_span::{BytePos, DUMMY_SP, Span};
use rustc_type_ir::region_constraint::evaluate_solver_constraint;

use super::SolverRegionConstraint;

fn and(constraints: Vec<SolverRegionConstraint<'static>>) -> SolverRegionConstraint<'static> {
SolverRegionConstraint::And(constraints.into_boxed_slice())
}

fn or(constraints: Vec<SolverRegionConstraint<'static>>) -> SolverRegionConstraint<'static> {
SolverRegionConstraint::Or(constraints.into_boxed_slice())
}

fn ambiguity() -> SolverRegionConstraint<'static> {
SolverRegionConstraint::Ambiguity(DUMMY_SP)
}

#[test]
fn evaluation_is_span_agnostic() {
let constraints = [
ambiguity(),
and(vec![]),
or(vec![]),
and(vec![and(vec![]), ambiguity()]),
and(vec![ambiguity(), or(vec![])]),
or(vec![or(vec![]), ambiguity()]),
or(vec![ambiguity(), and(vec![])]),
and(vec![or(vec![or(vec![]), ambiguity()]), or(vec![ambiguity(), and(vec![])])]),
];

for constraint in constraints {
let expected = evaluate_solver_constraint(&constraint.clone().without_spans());
let actual = evaluate_solver_constraint(&constraint).without_spans();
assert_eq!(actual, expected);
}
}

#[test]
fn evaluation_preserves_first_ambiguity_span() {
let first = Span::with_root_ctxt(BytePos(1), BytePos(2));
let second = Span::with_root_ctxt(BytePos(3), BytePos(4));

for constraint in [
and(vec![
SolverRegionConstraint::Ambiguity(first),
SolverRegionConstraint::Ambiguity(second),
]),
or(vec![
SolverRegionConstraint::Ambiguity(first),
SolverRegionConstraint::Ambiguity(second),
]),
] {
assert!(matches!(
evaluate_solver_constraint(&constraint),
SolverRegionConstraint::Ambiguity(span) if span == first
));
}
}
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 @@ -133,7 +133,7 @@ where
span,
),
ExternalRegionConstraints::NextGen(r) => {
delegate.register_solver_region_constraint(r.clone())
delegate.register_solver_region_constraint(r.clone(), span)
}
};
register_new_opaque_types(delegate, opaque_types, span);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,7 @@ where
}

pub(super) fn register_solver_region_constraint(&self, c: RegionConstraint<I>) {
self.delegate.register_solver_region_constraint(c);
self.delegate.register_solver_region_constraint(c, self.origin_span);
}

pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: Region<I>) {
Expand Down
Loading
Loading