Skip to content

Commit 5e6027c

Browse files
matthewjasperlqd
authored andcommitted
Track causes for universes created during borrowck
1 parent e271383 commit 5e6027c

File tree

9 files changed

+329
-129
lines changed

9 files changed

+329
-129
lines changed

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1506,7 +1506,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
15061506
self.inner.borrow_mut().projection_cache().clear();
15071507
}
15081508

1509-
fn universe(&self) -> ty::UniverseIndex {
1509+
pub fn universe(&self) -> ty::UniverseIndex {
15101510
self.universe.get()
15111511
}
15121512

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use rustc_infer::infer::canonical::Canonical;
2+
use rustc_middle::ty::{self, Ty, TypeFoldable};
3+
use rustc_span::Span;
4+
use rustc_trait_selection::traits::query::type_op;
5+
6+
use std::fmt;
7+
use std::rc::Rc;
8+
9+
use crate::borrow_check::region_infer::values::RegionElement;
10+
use crate::borrow_check::MirBorrowckCtxt;
11+
12+
#[derive(Clone)]
13+
crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
14+
15+
/// What operation a universe was created for.
16+
#[derive(Clone)]
17+
enum UniverseInfoInner<'tcx> {
18+
/// Relating two types which have binders.
19+
RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
20+
/// Created from performing a `TypeOp`.
21+
TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
22+
/// Any other reason.
23+
Other,
24+
}
25+
26+
impl UniverseInfo<'tcx> {
27+
crate fn other() -> UniverseInfo<'tcx> {
28+
UniverseInfo(UniverseInfoInner::Other)
29+
}
30+
31+
crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
32+
UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
33+
}
34+
35+
crate fn _report_error(
36+
&self,
37+
_mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
38+
_placeholder: ty::PlaceholderRegion,
39+
_error_element: RegionElement,
40+
_span: Span,
41+
) {
42+
todo!();
43+
}
44+
}
45+
46+
crate trait ToUniverseInfo<'tcx> {
47+
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
48+
}
49+
50+
impl<'tcx> ToUniverseInfo<'tcx>
51+
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
52+
{
53+
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
54+
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
55+
_canonical_query: self,
56+
_base_universe: base_universe,
57+
})))
58+
}
59+
}
60+
61+
impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
62+
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
63+
{
64+
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
65+
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
66+
_canonical_query: self,
67+
_base_universe: base_universe,
68+
})))
69+
}
70+
}
71+
72+
impl<'tcx> ToUniverseInfo<'tcx>
73+
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
74+
{
75+
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
76+
// Ascribe user type isn't usually called on types that have different
77+
// bound regions.
78+
UniverseInfo::other()
79+
}
80+
}
81+
82+
impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
83+
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
84+
// We can't rerun custom type ops.
85+
UniverseInfo::other()
86+
}
87+
}
88+
89+
#[allow(unused_lifetimes)]
90+
trait TypeOpInfo<'tcx> {
91+
// TODO: Methods for rerunning type op and reporting an error
92+
}
93+
94+
struct PredicateQuery<'tcx> {
95+
_canonical_query:
96+
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
97+
_base_universe: ty::UniverseIndex,
98+
}
99+
100+
impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> {}
101+
102+
struct NormalizeQuery<'tcx, T> {
103+
_canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
104+
_base_universe: ty::UniverseIndex,
105+
}
106+
107+
impl<T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T> where
108+
T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx
109+
{
110+
}

compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ mod outlives_suggestion;
2828
mod region_name;
2929
mod var_name;
3030

31+
mod bound_region_errors;
3132
mod conflict_errors;
3233
mod explain_borrow;
3334
mod move_errors;
3435
mod mutability_errors;
3536
mod region_errors;
3637

38+
crate use bound_region_errors::{ToUniverseInfo, UniverseInfo};
3739
crate use mutability_errors::AccessKind;
3840
crate use outlives_suggestion::OutlivesSuggestionBuilder;
3941
crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};

compiler/rustc_mir/src/borrow_check/nll.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
239239
outlives_constraints,
240240
member_constraints,
241241
closure_bounds_mapping,
242+
universe_causes,
242243
type_tests,
243244
} = constraints;
244245
let placeholder_indices = Rc::new(placeholder_indices);
@@ -260,6 +261,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
260261
outlives_constraints,
261262
member_constraints,
262263
closure_bounds_mapping,
264+
universe_causes,
263265
type_tests,
264266
liveness_constraints,
265267
elements,

compiler/rustc_mir/src/borrow_check/region_infer/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::borrow_check::{
2121
constraints::{
2222
graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
2323
},
24-
diagnostics::{RegionErrorKind, RegionErrors},
24+
diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo},
2525
member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
2626
nll::{PoloniusOutput, ToRegionVid},
2727
region_infer::reverse_sccs::ReverseSccGraph,
@@ -84,6 +84,9 @@ pub struct RegionInferenceContext<'tcx> {
8484
closure_bounds_mapping:
8585
FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
8686

87+
/// Map universe indexes to information on why we created it.
88+
_universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
89+
8790
/// Contains the minimum universe of any variable within the same
8891
/// SCC. We will ensure that no SCC contains values that are not
8992
/// visible from this index.
@@ -253,6 +256,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
253256
Location,
254257
FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
255258
>,
259+
universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
256260
type_tests: Vec<TypeTest<'tcx>>,
257261
liveness_constraints: LivenessValues<RegionVid>,
258262
elements: &Rc<RegionValueElements>,
@@ -293,6 +297,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
293297
member_constraints,
294298
member_constraints_applied: Vec::new(),
295299
closure_bounds_mapping,
300+
_universe_causes: universe_causes,
296301
scc_universes,
297302
scc_representatives,
298303
scc_values,
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
use std::fmt;
2+
3+
use rustc_hir as hir;
4+
use rustc_infer::infer::canonical::Canonical;
5+
use rustc_infer::traits::query::NoSolution;
6+
use rustc_middle::mir::ConstraintCategory;
7+
use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
8+
use rustc_span::Span;
9+
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
10+
use rustc_trait_selection::traits::query::Fallible;
11+
12+
use crate::borrow_check::diagnostics::{ToUniverseInfo, UniverseInfo};
13+
14+
use super::{Locations, NormalizeLocation, TypeChecker};
15+
16+
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
17+
/// Given some operation `op` that manipulates types, proves
18+
/// predicates, or otherwise uses the inference context, executes
19+
/// `op` and then executes all the further obligations that `op`
20+
/// returns. This will yield a set of outlives constraints amongst
21+
/// regions which are extracted and stored as having occurred at
22+
/// `locations`.
23+
///
24+
/// **Any `rustc_infer::infer` operations that might generate region
25+
/// constraints should occur within this method so that those
26+
/// constraints can be properly localized!**
27+
pub(super) fn fully_perform_op<R, Op>(
28+
&mut self,
29+
locations: Locations,
30+
category: ConstraintCategory,
31+
op: Op,
32+
) -> Fallible<R>
33+
where
34+
Op: type_op::TypeOp<'tcx, Output = R>,
35+
Canonical<'tcx, Op>: ToUniverseInfo<'tcx>,
36+
{
37+
let old_universe = self.infcx.universe();
38+
39+
let TypeOpOutput { output, constraints, canonicalized_query } =
40+
op.fully_perform(self.infcx)?;
41+
42+
if let Some(data) = &constraints {
43+
self.push_region_constraints(locations, category, data);
44+
}
45+
46+
let universe = self.infcx.universe();
47+
48+
if old_universe != universe {
49+
let universe_info = match canonicalized_query {
50+
Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe),
51+
None => UniverseInfo::other(),
52+
};
53+
for u in old_universe..universe {
54+
let info_universe =
55+
self.borrowck_context.constraints.universe_causes.push(universe_info.clone());
56+
assert_eq!(u.as_u32() + 1, info_universe.as_u32());
57+
}
58+
}
59+
60+
Ok(output)
61+
}
62+
63+
pub(super) fn instantiate_canonical_with_fresh_inference_vars<T>(
64+
&mut self,
65+
span: Span,
66+
canonical: &Canonical<'tcx, T>,
67+
) -> T
68+
where
69+
T: TypeFoldable<'tcx>,
70+
{
71+
let (instantiated, _) =
72+
self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
73+
74+
for _ in 0..canonical.max_universe.as_u32() {
75+
let info = UniverseInfo::other();
76+
self.borrowck_context.constraints.universe_causes.push(info);
77+
}
78+
79+
instantiated
80+
}
81+
82+
pub(super) fn prove_trait_ref(
83+
&mut self,
84+
trait_ref: ty::TraitRef<'tcx>,
85+
locations: Locations,
86+
category: ConstraintCategory,
87+
) {
88+
self.prove_predicates(
89+
Some(ty::PredicateKind::Trait(ty::TraitPredicate {
90+
trait_ref,
91+
constness: hir::Constness::NotConst,
92+
})),
93+
locations,
94+
category,
95+
);
96+
}
97+
98+
pub(super) fn normalize_and_prove_instantiated_predicates(
99+
&mut self,
100+
instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
101+
locations: Locations,
102+
) {
103+
for predicate in instantiated_predicates.predicates {
104+
let predicate = self.normalize(predicate, locations);
105+
self.prove_predicate(predicate, locations, ConstraintCategory::Boring);
106+
}
107+
}
108+
109+
pub(super) fn prove_predicates(
110+
&mut self,
111+
predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
112+
locations: Locations,
113+
category: ConstraintCategory,
114+
) {
115+
for predicate in predicates {
116+
let predicate = predicate.to_predicate(self.tcx());
117+
debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,);
118+
119+
self.prove_predicate(predicate, locations, category);
120+
}
121+
}
122+
123+
pub(super) fn prove_predicate(
124+
&mut self,
125+
predicate: ty::Predicate<'tcx>,
126+
locations: Locations,
127+
category: ConstraintCategory,
128+
) {
129+
debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,);
130+
131+
let param_env = self.param_env;
132+
self.fully_perform_op(
133+
locations,
134+
category,
135+
param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
136+
)
137+
.unwrap_or_else(|NoSolution| {
138+
span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
139+
})
140+
}
141+
142+
pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
143+
where
144+
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
145+
{
146+
debug!("normalize(value={:?}, location={:?})", value, location);
147+
let param_env = self.param_env;
148+
self.fully_perform_op(
149+
location.to_locations(),
150+
ConstraintCategory::Boring,
151+
param_env.and(type_op::normalize::Normalize::new(value)),
152+
)
153+
.unwrap_or_else(|NoSolution| {
154+
span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
155+
value
156+
})
157+
}
158+
}

compiler/rustc_mir/src/borrow_check/type_check/input_output.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
4444
// Instantiate the canonicalized variables from
4545
// user-provided signature (e.g., the `_` in the code
4646
// above) with fresh variables.
47-
let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
47+
let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
4848
body.span,
4949
&user_provided_poly_sig,
5050
);

0 commit comments

Comments
 (0)