Skip to content

Commit 295ad30

Browse files
committed
Auto merge of #53745 - nikomatsakis:nll-issue-53570, r=pnkfelix
do not propagate closure requirements if we can prove them locally Fixes #53570 cc @mikhail-m1 -- you're the one who last touched this code r? @pnkfelix
2 parents fc81e36 + bb8c4c0 commit 295ad30

19 files changed

+178
-80
lines changed

src/librustc_mir/borrow_check/nll/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ fn dump_annotation<'a, 'gcx, 'tcx>(
276276
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
277277
mir: &Mir<'tcx>,
278278
mir_def_id: DefId,
279-
regioncx: &RegionInferenceContext,
279+
regioncx: &RegionInferenceContext<'tcx>,
280280
closure_region_requirements: &Option<ClosureRegionRequirements>,
281281
errors_buffer: &mut Vec<Diagnostic>,
282282
) {
@@ -299,7 +299,7 @@ fn dump_annotation<'a, 'gcx, 'tcx>(
299299
.diagnostic()
300300
.span_note_diag(mir.span, "External requirements");
301301

302-
regioncx.annotate(&mut err);
302+
regioncx.annotate(tcx, &mut err);
303303

304304
err.note(&format!(
305305
"number of external vids: {}",
@@ -319,7 +319,7 @@ fn dump_annotation<'a, 'gcx, 'tcx>(
319319
.sess
320320
.diagnostic()
321321
.span_note_diag(mir.span, "No external requirements");
322-
regioncx.annotate(&mut err);
322+
regioncx.annotate(tcx, &mut err);
323323

324324
err.buffer(errors_buffer);
325325
}

src/librustc_mir/borrow_check/nll/region_infer/annotation.rs

-56
This file was deleted.

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

+41-21
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,10 @@ use rustc::util::common;
2929
use rustc_data_structures::graph::scc::Sccs;
3030
use rustc_data_structures::indexed_set::IdxSet;
3131
use rustc_data_structures::indexed_vec::IndexVec;
32-
use rustc_errors::Diagnostic;
32+
use rustc_errors::{DiagnosticBuilder, Diagnostic};
3333

3434
use std::rc::Rc;
3535

36-
mod annotation;
3736
mod dump_mir;
3837
mod error_reporting;
3938
mod graphviz;
@@ -359,6 +358,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
359358
self.universal_regions.to_region_vid(r)
360359
}
361360

361+
/// Add annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`.
362+
crate fn annotate(&self, tcx: TyCtxt<'_, '_, 'tcx>, err: &mut DiagnosticBuilder<'_>) {
363+
self.universal_regions.annotate(tcx, err)
364+
}
365+
362366
/// Returns true if the region `r` contains the point `p`.
363367
///
364368
/// Panics if called before `solve()` executes,
@@ -686,7 +690,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
686690
test: _,
687691
} = type_test;
688692

689-
690693
let generic_ty = generic_kind.to_ty(tcx);
691694
let subject = match self.try_promote_type_test_subject(infcx, generic_ty) {
692695
Some(s) => s,
@@ -698,20 +701,38 @@ impl<'tcx> RegionInferenceContext<'tcx> {
698701
// `ClosureOutlivesRequirement`.
699702
let r_scc = self.constraint_sccs.scc(*lower_bound);
700703
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
704+
// Check whether we can already prove that the "subject" outlives `ur`.
705+
// If so, we don't have to propagate this requirement to our caller.
706+
//
707+
// To continue the example from the function, if we are trying to promote
708+
// a requirement that `T: 'X`, and we know that `'X = '1 + '2` (i.e., the union
709+
// `'1` and `'2`), then in this loop `ur` will be `'1` (and `'2`). So here
710+
// we check whether `T: '1` is something we *can* prove. If so, no need
711+
// to propagate that requirement.
712+
//
713+
// This is needed because -- particularly in the case
714+
// where `ur` is a local bound -- we are sometimes in a
715+
// position to prove things that our caller cannot. See
716+
// #53570 for an example.
717+
if self.eval_region_test(mir, ur, &type_test.test) {
718+
continue;
719+
}
720+
721+
debug!("try_promote_type_test: ur={:?}", ur);
722+
701723
let non_local_ub = self.universal_region_relations.non_local_upper_bound(ur);
724+
debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
702725

703726
assert!(self.universal_regions.is_universal_region(non_local_ub));
704-
assert!(
705-
!self
706-
.universal_regions
707-
.is_local_free_region(non_local_ub)
708-
);
727+
assert!(!self.universal_regions.is_local_free_region(non_local_ub));
709728

710-
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
729+
let requirement = ClosureOutlivesRequirement {
711730
subject,
712731
outlived_free_region: non_local_ub,
713732
blame_span: locations.span(mir),
714-
});
733+
};
734+
debug!("try_promote_type_test: pushing {:#?}", requirement);
735+
propagated_outlives_requirements.push(requirement);
715736
}
716737
true
717738
}
@@ -917,8 +938,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
917938
// now). Therefore, the sup-region outlives the sub-region if,
918939
// for each universal region R1 in the sub-region, there
919940
// exists some region R2 in the sup-region that outlives R1.
920-
let universal_outlives = self
921-
.scc_values
941+
let universal_outlives = self.scc_values
922942
.universal_regions_outlived_by(sub_region_scc)
923943
.all(|r1| {
924944
self.scc_values
@@ -1029,8 +1049,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
10291049
// (because `fr` includes `end(o)`).
10301050
for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) {
10311051
// If it is known that `fr: o`, carry on.
1032-
if self
1033-
.universal_region_relations
1052+
if self.universal_region_relations
10341053
.outlives(longer_fr, shorter_fr)
10351054
{
10361055
continue;
@@ -1046,8 +1065,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
10461065
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
10471066
// Shrink `fr` until we find a non-local region (if we do).
10481067
// We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
1049-
if let Some(fr_minus) = self
1050-
.universal_region_relations
1068+
if let Some(fr_minus) = self.universal_region_relations
10511069
.non_local_lower_bound(longer_fr)
10521070
{
10531071
debug!("check_universal_region: fr_minus={:?}", fr_minus);
@@ -1056,8 +1074,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
10561074
// region. (We always will.) We'll call that
10571075
// `shorter_fr+` -- it's ever so slightly larger than
10581076
// `fr`.
1059-
let shorter_fr_plus = self
1060-
.universal_region_relations
1077+
let shorter_fr_plus = self.universal_region_relations
10611078
.non_local_upper_bound(shorter_fr);
10621079
debug!(
10631080
"check_universal_region: shorter_fr_plus={:?}",
@@ -1117,8 +1134,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11171134
let error_region = match error_element {
11181135
RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
11191136
RegionElement::RootUniversalRegion(r) => r,
1120-
RegionElement::SubUniversalRegion(error_ui) => self
1121-
.definitions
1137+
RegionElement::SubUniversalRegion(error_ui) => self.definitions
11221138
.iter_enumerated()
11231139
.filter_map(|(r, definition)| match definition.origin {
11241140
NLLRegionVariableOrigin::BoundRegion(ui) if error_ui == ui => Some(r),
@@ -1215,7 +1231,11 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi
12151231
// into a vector. These are the regions that we will be
12161232
// relating to one another.
12171233
let closure_mapping = &UniversalRegions::closure_mapping(
1218-
tcx, user_closure_ty, self.num_external_vids, tcx.closure_base_def_id(closure_def_id));
1234+
tcx,
1235+
user_closure_ty,
1236+
self.num_external_vids,
1237+
tcx.closure_base_def_id(closure_def_id),
1238+
);
12191239
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
12201240

12211241
// Create the predicates.

src/librustc_mir/borrow_check/nll/universal_regions.rs

+64
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use rustc::ty::subst::Substs;
3131
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty, TyCtxt};
3232
use rustc::util::nodemap::FxHashMap;
3333
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
34+
use rustc_errors::DiagnosticBuilder;
3435
use std::iter;
3536
use syntax::ast;
3637

@@ -310,6 +311,69 @@ impl<'tcx> UniversalRegions<'tcx> {
310311
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
311312
self.indices.to_region_vid(r)
312313
}
314+
315+
/// As part of the NLL unit tests, you can annotate a function with
316+
/// `#[rustc_regions]`, and we will emit information about the region
317+
/// inference context and -- in particular -- the external constraints
318+
/// that this region imposes on others. The methods in this file
319+
/// handle the part about dumping the inference context internal
320+
/// state.
321+
crate fn annotate(&self, tcx: TyCtxt<'_, '_, 'tcx>, err: &mut DiagnosticBuilder<'_>) {
322+
match self.defining_ty {
323+
DefiningTy::Closure(def_id, substs) => {
324+
err.note(&format!(
325+
"defining type: {:?} with closure substs {:#?}",
326+
def_id,
327+
&substs.substs[..]
328+
));
329+
330+
// FIXME: It'd be nice to print the late-bound regions
331+
// here, but unfortunately these wind up stored into
332+
// tests, and the resulting print-outs include def-ids
333+
// and other things that are not stable across tests!
334+
// So we just include the region-vid. Annoying.
335+
let closure_base_def_id = tcx.closure_base_def_id(def_id);
336+
for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
337+
err.note(&format!(
338+
"late-bound region is {:?}",
339+
self.to_region_vid(r),
340+
));
341+
});
342+
}
343+
DefiningTy::Generator(def_id, substs, _) => {
344+
err.note(&format!(
345+
"defining type: {:?} with generator substs {:#?}",
346+
def_id,
347+
&substs.substs[..]
348+
));
349+
350+
// FIXME: As above, we'd like to print out the region
351+
// `r` but doing so is not stable across architectures
352+
// and so forth.
353+
let closure_base_def_id = tcx.closure_base_def_id(def_id);
354+
for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
355+
err.note(&format!(
356+
"late-bound region is {:?}",
357+
self.to_region_vid(r),
358+
));
359+
});
360+
}
361+
DefiningTy::FnDef(def_id, substs) => {
362+
err.note(&format!(
363+
"defining type: {:?} with substs {:#?}",
364+
def_id,
365+
&substs[..]
366+
));
367+
}
368+
DefiningTy::Const(def_id, substs) => {
369+
err.note(&format!(
370+
"defining constant type: {:?} with substs {:#?}",
371+
def_id,
372+
&substs[..]
373+
));
374+
}
375+
}
376+
}
313377
}
314378

315379
struct UniversalRegionsBuilder<'cx, 'gcx: 'tcx, 'tcx: 'cx> {

src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ LL | | },
1212
i16,
1313
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
1414
]
15+
= note: late-bound region is '_#4r
16+
= note: late-bound region is '_#5r
17+
= note: late-bound region is '_#6r
1518

1619
error: unsatisfied lifetime constraints
1720
--> $DIR/propagate-approximated-fail-no-postdom.rs:56:13

src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ LL | | });
1414
i16,
1515
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
1616
]
17+
= note: late-bound region is '_#3r
18+
= note: late-bound region is '_#4r
1719
= note: number of external vids: 5
1820
= note: where '_#1r: '_#2r
1921

src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ LL | | });
1515
i16,
1616
for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) u32>))
1717
]
18+
= note: late-bound region is '_#2r
19+
= note: late-bound region is '_#3r
1820
= note: number of external vids: 4
1921
= note: where '_#1r: '_#0r
2022

src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ LL | | });
1414
i16,
1515
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
1616
]
17+
= note: late-bound region is '_#3r
18+
= note: late-bound region is '_#4r
1719
= note: number of external vids: 5
1820
= note: where '_#1r: '_#0r
1921

src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ LL | | });
1414
i16,
1515
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
1616
]
17+
= note: late-bound region is '_#3r
18+
= note: late-bound region is '_#4r
1719
= note: number of external vids: 5
1820
= note: where '_#1r: '_#2r
1921

src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ LL | | },
1212
i16,
1313
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
1414
]
15+
= note: late-bound region is '_#3r
1516
= note: number of external vids: 4
1617
= note: where '_#1r: '_#2r
1718

src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ LL | | });
1313
i16,
1414
for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
1515
]
16+
= note: late-bound region is '_#2r
17+
= note: late-bound region is '_#3r
1618

1719
error: unsatisfied lifetime constraints
1820
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9

src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ LL | | });
1313
i16,
1414
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
1515
]
16+
= note: late-bound region is '_#3r
17+
= note: late-bound region is '_#4r
1618

1719
error: unsatisfied lifetime constraints
1820
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:9

0 commit comments

Comments
 (0)