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
14 changes: 12 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>(
(RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
_ => a_region == b_region,
};
let mut check = |c: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match c.kind {
let mut check = |c: Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match c.kind {
ConstraintKind::RegSubReg
if ((exact && c.sup == placeholder_region)
|| (!exact && regions_the_same(c.sup, placeholder_region)))
Expand All @@ -467,13 +467,23 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>(
{
Some((c.sub, cause.clone()))
}
_ => None,
ConstraintKind::VarSubVar
| ConstraintKind::RegSubVar
| ConstraintKind::VarSubReg
| ConstraintKind::RegSubReg => None,

ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => {
unreachable!()
}
};

let mut find_culprit = |exact_match: bool| {
region_constraints
.constraints
.iter()
.flat_map(|(constraint, cause)| {
constraint.iter_outlives().map(move |constraint| (constraint, cause))
})
.find_map(|(constraint, cause)| check(constraint, cause, exact_match))
};

Expand Down
16 changes: 11 additions & 5 deletions compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,14 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {

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

for &(predicate, constraint_category) in outlives {
self.convert(predicate, constraint_category, &assumptions);
for &(constraint, constraint_category) in constraints {
constraint.iter_outlives().for_each(|predicate| {
self.convert(predicate, constraint_category, &assumptions);
});
}
}

Expand Down Expand Up @@ -292,8 +294,12 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
) {
Ok(TypeOpOutput { output: ty, constraints, .. }) => {
// FIXME(higher_ranked_auto): What should we do with the assumptions here?
if let Some(QueryRegionConstraints { outlives, assumptions: _ }) = constraints {
next_outlives_predicates.extend(outlives.iter().copied());
if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints {
next_outlives_predicates.extend(constraints.iter().flat_map(
|(constraint, category)| {
constraint.iter_outlives().map(|outlives| (outlives, *category))
},
));
}
ty
}
Expand Down
59 changes: 36 additions & 23 deletions compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::infer::canonical::{
Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
QueryRegionConstraints, QueryResponse,
};
use crate::infer::region_constraints::RegionConstraintData;
use crate::infer::region_constraints::{ConstraintKind, RegionConstraintData};
use crate::infer::{
DefineOpaqueTypes, InferCtxt, InferOk, InferResult, OpaqueTypeStorageEntries, SubregionOrigin,
TypeOutlivesConstraint,
Expand Down Expand Up @@ -188,9 +188,16 @@ impl<'tcx> InferCtxt<'tcx> {
let InferOk { value: result_args, obligations } =
self.query_response_instantiation(cause, param_env, original_values, query_response)?;

for (predicate, _category) in &query_response.value.region_constraints.outlives {
let predicate = instantiate_value(self.tcx, &result_args, *predicate);
self.register_outlives_constraint(predicate, cause);
for (constraint, _category) in &query_response.value.region_constraints.constraints {
let constraint = instantiate_value(self.tcx, &result_args, *constraint);
match constraint {
ty::RegionConstraint::Outlives(predicate) => {
self.register_outlives_constraint(predicate, cause);
}
ty::RegionConstraint::Eq(predicate) => {
self.register_region_eq_constraint(predicate, cause);
}
}
}

for assumption in &query_response.value.region_constraints.assumptions {
Expand Down Expand Up @@ -277,14 +284,11 @@ impl<'tcx> InferCtxt<'tcx> {
}

(GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
if v_o != v_r {
output_query_region_constraints
.outlives
.push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
output_query_region_constraints
.outlives
.push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
output_query_region_constraints.constraints.push((
ty::RegionEqPredicate(v_o.into(), v_r).into(),
constraint_category,
));
}
}

Expand All @@ -311,13 +315,12 @@ impl<'tcx> InferCtxt<'tcx> {
}

// ...also include the other query region constraints from the query.
output_query_region_constraints.outlives.extend(
query_response.value.region_constraints.outlives.iter().filter_map(|&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` cases.
let ty::OutlivesPredicate(k1, r2) = r_c.0;
if k1 != r2.into() { Some(r_c) } else { None }
// Screen out `'a: 'a` or `'a == 'a` cases.
if r_c.0.is_trivial() { None } else { Some(r_c) }
}),
);

Expand Down Expand Up @@ -611,20 +614,30 @@ pub fn make_query_region_constraints<'tcx>(

debug!(?constraints);

let outlives: Vec<_> = constraints
let constraints: Vec<_> = constraints
.iter()
.map(|(c, origin)| {
// Swap regions because we are going from sub (<=) to outlives (>=).
let constraint = ty::OutlivesPredicate(c.sup.into(), c.sub);
(constraint, origin.to_constraint_category())
.map(|(c, origin)| match c.kind {
ConstraintKind::VarSubVar
| ConstraintKind::RegSubVar
| ConstraintKind::VarSubReg
| ConstraintKind::RegSubReg => {
// Swap regions because we are going from sub (<=) to outlives (>=).
let constraint = ty::OutlivesPredicate(c.sup.into(), c.sub).into();
(constraint, origin.to_constraint_category())
}

ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => {
let constraint = ty::RegionEqPredicate(c.sup, c.sub).into();
(constraint, origin.to_constraint_category())
}
})
.chain(outlives_obligations.into_iter().map(|obl| {
(
ty::OutlivesPredicate(obl.sup_type.into(), obl.sub_region),
ty::OutlivesPredicate(obl.sup_type.into(), obl.sub_region).into(),
obl.origin.to_constraint_category(),
)
}))
.collect();

QueryRegionConstraints { outlives, assumptions }
QueryRegionConstraints { constraints, assumptions }
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,60 @@ pub(super) enum EdgeDirection {

/// Type alias for the pairs stored in [`RegionConstraintData::constraints`],
/// which we are indexing.
type ConstraintPair<'tcx> = (Constraint<'tcx>, SubregionOrigin<'tcx>);
type ConstraintPair<'data, 'tcx> = (Constraint<'tcx>, &'data SubregionOrigin<'tcx>);

/// An index from region variables to their corresponding constraint edges,
/// used on some error paths.
pub(super) struct IndexedConstraintEdges<'data, 'tcx> {
out_edges: IndexVec<RegionVid, Vec<&'data ConstraintPair<'tcx>>>,
in_edges: IndexVec<RegionVid, Vec<&'data ConstraintPair<'tcx>>>,
out_edges: IndexVec<RegionVid, Vec<ConstraintPair<'data, 'tcx>>>,
in_edges: IndexVec<RegionVid, Vec<ConstraintPair<'data, 'tcx>>>,
}

impl<'data, 'tcx> IndexedConstraintEdges<'data, 'tcx> {
pub(super) fn build_index(num_vars: usize, data: &'data RegionConstraintData<'tcx>) -> Self {
let mut out_edges = IndexVec::from_fn_n(|_| vec![], num_vars);
let mut in_edges = IndexVec::from_fn_n(|_| vec![], num_vars);

for pair @ (c, _) in &data.constraints {
for pair @ (c, _) in data
.constraints
.iter()
.flat_map(|(c, origin)| c.iter_outlives().map(move |c| (c, origin)))
{
// Only push a var out-edge for `VarSub...` constraints.
match c.kind {
ConstraintKind::VarSubVar | ConstraintKind::VarSubReg => {
out_edges[c.sub.as_var()].push(pair)
out_edges[c.sub.as_var()].push(pair);
}

ConstraintKind::RegSubVar | ConstraintKind::RegSubReg => {}

ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => {
unreachable!();
}
}
Comment thread
lcnr marked this conversation as resolved.
}

// FIXME: We should merge this loop with the above one eventually.
// Index in-edges in reverse order, to match what current tests expect.
// (It's unclear whether this is important or not.)
for pair @ (c, _) in data.constraints.iter().rev() {

for pair @ (c, _) in data
.constraints
.iter()
.rev()
.flat_map(|(c, origin)| c.iter_outlives().map(move |c| (c, origin)))
{
// Only push a var in-edge for `...SubVar` constraints.
match c.kind {
ConstraintKind::VarSubVar | ConstraintKind::RegSubVar => {
in_edges[c.sup.as_var()].push(pair)
in_edges[c.sup.as_var()].push(pair);
}

ConstraintKind::VarSubReg | ConstraintKind::RegSubReg => {}

ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => {
unreachable!();
}
}
}

Expand All @@ -58,7 +79,7 @@ impl<'data, 'tcx> IndexedConstraintEdges<'data, 'tcx> {
&self,
region_vid: RegionVid,
dir: EdgeDirection,
) -> &[&'data ConstraintPair<'tcx>] {
) -> &[ConstraintPair<'data, 'tcx>] {
let edges = match dir {
EdgeDirection::Out => &self.out_edges,
EdgeDirection::In => &self.in_edges,
Expand Down
28 changes: 26 additions & 2 deletions compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ pub(crate) fn resolve<'tcx>(
var_infos: VarInfos<'tcx>,
data: RegionConstraintData<'tcx>,
) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
assert!(
data.constraints.iter().all(|(c, _)| match c.kind {
ConstraintKind::VarSubVar
| ConstraintKind::RegSubVar
| ConstraintKind::VarSubReg
| ConstraintKind::RegSubReg => true,

ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => false,
}),
"Every constraint should be decomposed into outlives here"
);

let mut errors = vec![];
let mut resolver = LexicalResolver { region_rels, var_infos, data };
let values = resolver.infer_variable_values(&mut errors);
Expand Down Expand Up @@ -279,6 +291,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// is done, in `collect_errors`.
continue;
}

ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => {
unreachable!()
}
}
}

Expand Down Expand Up @@ -575,6 +591,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
*sub_data = VarValue::ErrorValue;
}
}

ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => {
unreachable!()
}
}
}

Expand Down Expand Up @@ -852,19 +872,23 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}

ConstraintKind::RegSubVar => {
let origin = origin.clone();
let origin = (*origin).clone();
state.result.push(RegionAndOrigin { region: c.sub, origin });
}

ConstraintKind::VarSubReg => {
let origin = origin.clone();
let origin = (*origin).clone();
state.result.push(RegionAndOrigin { region: c.sup, origin });
}

ConstraintKind::RegSubReg => panic!(
"cannot reach reg-sub-reg edge in region inference \
post-processing"
),

ConstraintKind::VarEqVar
| ConstraintKind::VarEqReg
| ConstraintKind::RegEqReg => unreachable!(),
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,16 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b);
}

#[instrument(skip(self), level = "debug")]
pub fn equate_regions(
&self,
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) {
self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(origin, a, b);
}

/// Processes a `Coerce` predicate from the fulfillment context.
/// This is NOT the preferred way to handle coercion, which is to
/// invoke `FnCtxt::coerce` or a similar method (see `coercion.rs`).
Expand Down
20 changes: 19 additions & 1 deletion compiler/rustc_infer/src/infer/outlives/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Various code related to computing outlives relations.

use std::iter;

use rustc_data_structures::undo_log::UndoLogs;
use rustc_middle::traits::query::{NoSolution, OutlivesBound};
use rustc_middle::ty;
Expand Down Expand Up @@ -67,14 +69,30 @@ impl<'tcx> InferCtxt<'tcx> {
inner.region_constraint_storage.take().expect("regions already resolved")
};

storage.data.constraints = storage
.data
.constraints
.iter()
.flat_map(|(constraint, origin)| {
constraint.iter_outlives().zip(iter::repeat_with(|| origin.clone()))
})
.collect();

// Filter out any region-region outlives assumptions that are implied by
// coroutine well-formedness.
if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions {
storage.data.constraints.retain(|(c, _)| match c.kind {
ConstraintKind::RegSubReg => !outlives_env
.higher_ranked_assumptions()
.contains(&ty::OutlivesPredicate(c.sup.into(), c.sub)),
_ => true,

ConstraintKind::VarSubVar
| ConstraintKind::RegSubVar
| ConstraintKind::VarSubReg => true,

ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => {
unreachable!();
}
});
}

Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_infer/src/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ impl<'tcx> InferCtxt<'tcx> {
}
}

pub fn register_region_eq_constraint(
&self,
ty::RegionEqPredicate(r_a, r_b): ty::RegionEqPredicate<'tcx>,
cause: &ObligationCause<'tcx>,
) {
let origin = SubregionOrigin::from_obligation_cause(cause, || {
SubregionOrigin::RelateRegionParamBound(cause.span, None)
});
self.equate_regions(origin, r_a, r_b);
}

pub fn register_region_outlives_constraint(
&self,
ty::OutlivesPredicate(r_a, r_b): ty::RegionOutlivesPredicate<'tcx>,
Expand Down
Loading
Loading