Skip to content

Commit 13fd658

Browse files
authored
Rollup merge of rust-lang#58347 - matthewjasper:closure-bounds-fixes, r=pnkfelix
Closure bounds fixes * Ensures that "nice region errors" are buffered so that they are sorted and migrated correctly. * Propagates fewer constraints for closures (cc rust-lang#58178) * Propagate constraints from closures more precisely (rust-lang#58127) Closes rust-lang#58127 r? @nikomatsakis
2 parents 44060a0 + 79e8c31 commit 13fd658

File tree

7 files changed

+234
-112
lines changed

7 files changed

+234
-112
lines changed

src/librustc/infer/error_reporting/nice_region_error/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use crate::infer::InferCtxt;
22
use crate::infer::lexical_region_resolve::RegionResolutionError;
33
use crate::infer::lexical_region_resolve::RegionResolutionError::*;
4-
use syntax::source_map::Span;
54
use crate::ty::{self, TyCtxt};
65
use crate::util::common::ErrorReported;
6+
use errors::DiagnosticBuilder;
7+
use syntax::source_map::Span;
78

89
mod different_lifetimes;
910
mod find_anon_type;
@@ -59,7 +60,7 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
5960
self.infcx.tcx
6061
}
6162

62-
pub fn try_report_from_nll(&self) -> Option<ErrorReported> {
63+
pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'cx>> {
6364
// Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
6465
// the nice region errors are required when running under the MIR borrow checker.
6566
self.try_report_named_anon_conflict()
@@ -68,6 +69,7 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
6869

6970
pub fn try_report(&self) -> Option<ErrorReported> {
7071
self.try_report_from_nll()
72+
.map(|mut diag| { diag.emit(); ErrorReported })
7173
.or_else(|| self.try_report_anon_anon_conflict())
7274
.or_else(|| self.try_report_outlives_closure())
7375
.or_else(|| self.try_report_static_impl_trait())

src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
//! where one region is named and the other is anonymous.
33
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
44
use crate::ty;
5-
use crate::util::common::ErrorReported;
6-
use errors::Applicability;
5+
use errors::{Applicability, DiagnosticBuilder};
76

87
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
98
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
109
/// an anonymous region, emit an descriptive diagnostic error.
11-
pub(super) fn try_report_named_anon_conflict(&self) -> Option<ErrorReported> {
10+
pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'a>> {
1211
let (span, sub, sup) = self.get_regions();
1312

1413
debug!(
@@ -96,21 +95,23 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
9695
("parameter type".to_owned(), "type".to_owned())
9796
};
9897

99-
struct_span_err!(
98+
let mut diag = struct_span_err!(
10099
self.tcx().sess,
101100
span,
102101
E0621,
103102
"explicit lifetime required in {}",
104103
error_var
105-
).span_suggestion(
106-
new_ty_span,
107-
&format!("add explicit lifetime `{}` to {}", named, span_label_var),
108-
new_ty.to_string(),
109-
Applicability::Unspecified,
110-
)
111-
.span_label(span, format!("lifetime `{}` required", named))
112-
.emit();
113-
return Some(ErrorReported);
104+
);
105+
106+
diag.span_suggestion(
107+
new_ty_span,
108+
&format!("add explicit lifetime `{}` to {}", named, span_label_var),
109+
new_ty.to_string(),
110+
Applicability::Unspecified,
111+
)
112+
.span_label(span, format!("lifetime `{}` required", named));
113+
114+
Some(diag)
114115
}
115116

116117
// This method returns whether the given Region is Named

src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@ use crate::traits::{ObligationCause, ObligationCauseCode};
88
use crate::ty;
99
use crate::ty::error::ExpectedFound;
1010
use crate::ty::subst::Substs;
11-
use crate::util::common::ErrorReported;
1211
use crate::util::ppaux::RegionHighlightMode;
1312

1413
impl NiceRegionError<'me, 'gcx, 'tcx> {
1514
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
1615
/// an anonymous region, emit a descriptive diagnostic error.
17-
pub(super) fn try_report_placeholder_conflict(&self) -> Option<ErrorReported> {
16+
pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder<'me>> {
1817
match &self.error {
1918
///////////////////////////////////////////////////////////////////////////
2019
// NB. The ordering of cases in this match is very
@@ -178,7 +177,7 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
178177
trait_def_id: DefId,
179178
expected_substs: &'tcx Substs<'tcx>,
180179
actual_substs: &'tcx Substs<'tcx>,
181-
) -> ErrorReported {
180+
) -> DiagnosticBuilder<'me> {
182181
debug!(
183182
"try_report_placeholders_trait(\
184183
vid={:?}, \
@@ -295,8 +294,7 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
295294
any_self_ty_has_vid,
296295
);
297296

298-
err.emit();
299-
ErrorReported
297+
err
300298
}
301299

302300
/// Add notes with details about the expected and actual trait refs, with attention to cases

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
244244
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
245245
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
246246
let nice = NiceRegionError::new_from_span(infcx, span, o, f, Some(tables));
247-
if let Some(_error_reported) = nice.try_report_from_nll() {
247+
if let Some(diag) = nice.try_report_from_nll() {
248+
diag.buffer(errors_buffer);
248249
return;
249250
}
250251
}

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

+106-54
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc::mir::{
1515
ConstraintCategory, Local, Location, Mir,
1616
};
1717
use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
18-
use rustc::util::common;
18+
use rustc::util::common::{self, ErrorReported};
1919
use rustc_data_structures::bit_set::BitSet;
2020
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2121
use rustc_data_structures::graph::scc::Sccs;
@@ -763,20 +763,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
763763

764764
debug!("try_promote_type_test: ur={:?}", ur);
765765

766-
let non_local_ub = self.universal_region_relations.non_local_upper_bound(ur);
766+
let non_local_ub = self.universal_region_relations.non_local_upper_bounds(&ur);
767767
debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
768768

769-
assert!(self.universal_regions.is_universal_region(non_local_ub));
770-
assert!(!self.universal_regions.is_local_free_region(non_local_ub));
771-
772-
let requirement = ClosureOutlivesRequirement {
773-
subject,
774-
outlived_free_region: non_local_ub,
775-
blame_span: locations.span(mir),
776-
category: ConstraintCategory::Boring,
777-
};
778-
debug!("try_promote_type_test: pushing {:#?}", requirement);
779-
propagated_outlives_requirements.push(requirement);
769+
// This is slightly too conservative. To show T: '1, given `'2: '1`
770+
// and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to
771+
// avoid potential non-determinism we approximate this by requiring
772+
// T: '1 and T: '2.
773+
for &upper_bound in non_local_ub {
774+
debug_assert!(self.universal_regions.is_universal_region(upper_bound));
775+
debug_assert!(!self.universal_regions.is_local_free_region(upper_bound));
776+
777+
let requirement = ClosureOutlivesRequirement {
778+
subject,
779+
outlived_free_region: upper_bound,
780+
blame_span: locations.span(mir),
781+
category: ConstraintCategory::Boring,
782+
};
783+
debug!("try_promote_type_test: pushing {:#?}", requirement);
784+
propagated_outlives_requirements.push(requirement);
785+
}
780786
}
781787
true
782788
}
@@ -1157,63 +1163,109 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11571163
.is_none()
11581164
);
11591165

1166+
// Only check all of the relations for the main representative of each
1167+
// SCC, otherwise just check that we outlive said representative. This
1168+
// reduces the number of redundant relations propagated out of
1169+
// closures.
1170+
// Note that the representative will be a universal region if there is
1171+
// one in this SCC, so we will always check the representative here.
1172+
let representative = self.scc_representatives[longer_fr_scc];
1173+
if representative != longer_fr {
1174+
self.check_universal_region_relation(
1175+
longer_fr,
1176+
representative,
1177+
infcx,
1178+
mir,
1179+
mir_def_id,
1180+
propagated_outlives_requirements,
1181+
errors_buffer,
1182+
);
1183+
return;
1184+
}
1185+
11601186
// Find every region `o` such that `fr: o`
11611187
// (because `fr` includes `end(o)`).
11621188
for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) {
1163-
// If it is known that `fr: o`, carry on.
1164-
if self.universal_region_relations
1165-
.outlives(longer_fr, shorter_fr)
1166-
{
1167-
continue;
1189+
if let Some(ErrorReported) = self.check_universal_region_relation(
1190+
longer_fr,
1191+
shorter_fr,
1192+
infcx,
1193+
mir,
1194+
mir_def_id,
1195+
propagated_outlives_requirements,
1196+
errors_buffer,
1197+
) {
1198+
// continuing to iterate just reports more errors than necessary
1199+
return;
11681200
}
1201+
}
1202+
}
11691203

1170-
debug!(
1171-
"check_universal_region: fr={:?} does not outlive shorter_fr={:?}",
1172-
longer_fr, shorter_fr,
1173-
);
1204+
fn check_universal_region_relation(
1205+
&self,
1206+
longer_fr: RegionVid,
1207+
shorter_fr: RegionVid,
1208+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
1209+
mir: &Mir<'tcx>,
1210+
mir_def_id: DefId,
1211+
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
1212+
errors_buffer: &mut Vec<Diagnostic>,
1213+
) -> Option<ErrorReported> {
1214+
// If it is known that `fr: o`, carry on.
1215+
if self.universal_region_relations
1216+
.outlives(longer_fr, shorter_fr)
1217+
{
1218+
return None;
1219+
}
11741220

1175-
let blame_span_category = self.find_outlives_blame_span(mir, longer_fr, shorter_fr);
1176-
1177-
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
1178-
// Shrink `fr` until we find a non-local region (if we do).
1179-
// We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
1180-
if let Some(fr_minus) = self.universal_region_relations
1181-
.non_local_lower_bound(longer_fr)
1182-
{
1183-
debug!("check_universal_region: fr_minus={:?}", fr_minus);
1184-
1185-
// Grow `shorter_fr` until we find a non-local
1186-
// region. (We always will.) We'll call that
1187-
// `shorter_fr+` -- it's ever so slightly larger than
1188-
// `fr`.
1189-
let shorter_fr_plus = self.universal_region_relations
1190-
.non_local_upper_bound(shorter_fr);
1191-
debug!(
1192-
"check_universal_region: shorter_fr_plus={:?}",
1193-
shorter_fr_plus
1194-
);
1221+
debug!(
1222+
"check_universal_region_relation: fr={:?} does not outlive shorter_fr={:?}",
1223+
longer_fr, shorter_fr,
1224+
);
11951225

1226+
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
1227+
// Shrink `longer_fr` until we find a non-local region (if we do).
1228+
// We'll call it `fr-` -- it's ever so slightly smaller than
1229+
// `longer_fr`.
1230+
1231+
if let Some(fr_minus) = self
1232+
.universal_region_relations
1233+
.non_local_lower_bound(longer_fr)
1234+
{
1235+
debug!("check_universal_region: fr_minus={:?}", fr_minus);
1236+
1237+
let blame_span_category = self.find_outlives_blame_span(mir, longer_fr, shorter_fr);
1238+
1239+
// Grow `shorter_fr` until we find some non-local regions. (We
1240+
// always will.) We'll call them `shorter_fr+` -- they're ever
1241+
// so slightly larger than `shorter_fr`.
1242+
let shorter_fr_plus = self.universal_region_relations
1243+
.non_local_upper_bounds(&shorter_fr);
1244+
debug!(
1245+
"check_universal_region: shorter_fr_plus={:?}",
1246+
shorter_fr_plus
1247+
);
1248+
for &&fr in &shorter_fr_plus {
11961249
// Push the constraint `fr-: shorter_fr+`
11971250
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
11981251
subject: ClosureOutlivesSubject::Region(fr_minus),
1199-
outlived_free_region: shorter_fr_plus,
1252+
outlived_free_region: fr,
12001253
blame_span: blame_span_category.1,
12011254
category: blame_span_category.0,
12021255
});
1203-
continue;
12041256
}
1257+
return None;
12051258
}
1206-
1207-
// If we are not in a context where we can propagate
1208-
// errors, or we could not shrink `fr` to something
1209-
// smaller, then just report an error.
1210-
//
1211-
// Note: in this case, we use the unapproximated regions
1212-
// to report the error. This gives better error messages
1213-
// in some cases.
1214-
self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer);
1215-
return; // continuing to iterate just reports more errors than necessary
12161259
}
1260+
1261+
// If we are not in a context where we can't propagate errors, or we
1262+
// could not shrink `fr` to something smaller, then just report an
1263+
// error.
1264+
//
1265+
// Note: in this case, we use the unapproximated regions to report the
1266+
// error. This gives better error messages in some cases.
1267+
self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer);
1268+
Some(ErrorReported)
12171269
}
12181270

12191271
fn check_bound_universal_region<'gcx>(

0 commit comments

Comments
 (0)