Skip to content

Commit 00e314d

Browse files
committed
Add an optional Span to BrAnon and use it to print better error for HRTB error from generator interior
1 parent 1e1e5b8 commit 00e314d

File tree

23 files changed

+251
-63
lines changed

23 files changed

+251
-63
lines changed

compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs

+3
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ trait TypeOpInfo<'tcx> {
158158
error_region: Option<ty::Region<'tcx>>,
159159
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
160160

161+
#[instrument(level = "debug", skip(self, mbcx))]
161162
fn report_error(
162163
&self,
163164
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
@@ -167,6 +168,7 @@ trait TypeOpInfo<'tcx> {
167168
) {
168169
let tcx = mbcx.infcx.tcx;
169170
let base_universe = self.base_universe();
171+
debug!(?base_universe);
170172

171173
let Some(adjusted_universe) =
172174
placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
@@ -389,6 +391,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
389391
)
390392
}
391393

394+
#[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))]
392395
fn try_extract_error_from_region_constraints<'tcx>(
393396
infcx: &InferCtxt<'tcx>,
394397
placeholder_region: ty::Region<'tcx>,

compiler/rustc_borrowck/src/diagnostics/region_name.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
355355
})
356356
}
357357

358-
ty::BoundRegionKind::BrAnon(_) => None,
358+
ty::BoundRegionKind::BrAnon(..) => None,
359359
},
360360

361361
ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,

compiler/rustc_hir_analysis/src/astconv/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2976,15 +2976,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
29762976
) {
29772977
for br in referenced_regions.difference(&constrained_regions) {
29782978
let br_name = match *br {
2979-
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => {
2979+
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => {
29802980
"an anonymous lifetime".to_string()
29812981
}
29822982
ty::BrNamed(_, name) => format!("lifetime `{}`", name),
29832983
};
29842984

29852985
let mut err = generate_err(&br_name);
29862986

2987-
if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br {
2987+
if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) = *br {
29882988
// The only way for an anonymous lifetime to wind up
29892989
// in the return type but **also** be unconstrained is
29902990
// if it only appears in "associated types" in the

compiler/rustc_hir_analysis/src/check/intrinsic.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,18 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
134134
let name_str = intrinsic_name.as_str();
135135

136136
let bound_vars = tcx.mk_bound_variable_kinds(
137-
[ty::BoundVariableKind::Region(ty::BrAnon(0)), ty::BoundVariableKind::Region(ty::BrEnv)]
138-
.iter()
139-
.copied(),
137+
[
138+
ty::BoundVariableKind::Region(ty::BrAnon(0, None)),
139+
ty::BoundVariableKind::Region(ty::BrEnv),
140+
]
141+
.iter()
142+
.copied(),
140143
);
141144
let mk_va_list_ty = |mutbl| {
142145
tcx.lang_items().va_list().map(|did| {
143146
let region = tcx.mk_region(ty::ReLateBound(
144147
ty::INNERMOST,
145-
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) },
148+
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) },
146149
));
147150
let env_region = tcx.mk_region(ty::ReLateBound(
148151
ty::INNERMOST,
@@ -364,7 +367,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
364367
);
365368
let discriminant_def_id = assoc_items[0];
366369

367-
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
370+
let br =
371+
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
368372
(
369373
1,
370374
vec![
@@ -418,7 +422,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
418422
sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
419423

420424
sym::raw_eq => {
421-
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
425+
let br =
426+
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
422427
let param_ty =
423428
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0));
424429
(1, vec![param_ty; 2], tcx.types.bool)

compiler/rustc_hir_typeck/src/generator_interior/mod.rs

+64-24
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ use rustc_hir::def_id::DefId;
1313
use rustc_hir::hir_id::HirIdSet;
1414
use rustc_hir::intravisit::{self, Visitor};
1515
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
16+
use rustc_infer::infer::RegionVariableOrigin;
1617
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
17-
use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
18+
use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitable};
1819
use rustc_span::symbol::sym;
1920
use rustc_span::Span;
2021

@@ -211,43 +212,82 @@ pub fn resolve_interior<'a, 'tcx>(
211212

212213
debug!("types in generator {:?}, span = {:?}", types, body.value.span);
213214

214-
let mut counter = 0;
215+
// We want to deduplicate if the lifetimes are the same modulo some non-informative counter.
216+
// So, we need to actually do two passes: first by type to anonymize (preserving information
217+
// required for diagnostics), then a second pass over all captured types to reassign disjoint
218+
// region indices.
215219
let mut captured_tys = FxHashSet::default();
216220
let type_causes: Vec<_> = types
217221
.into_iter()
218222
.filter_map(|mut cause| {
219-
// Erase regions and canonicalize late-bound regions to deduplicate as many types as we
220-
// can.
221-
let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
222-
let erased = fcx.tcx.erase_regions(ty);
223-
if captured_tys.insert(erased) {
224-
// Replace all regions inside the generator interior with late bound regions.
225-
// Note that each region slot in the types gets a new fresh late bound region,
226-
// which means that none of the regions inside relate to any other, even if
227-
// typeck had previously found constraints that would cause them to be related.
228-
let folded = fcx.tcx.fold_regions(erased, |_, current_depth| {
229-
let br = ty::BoundRegion {
230-
var: ty::BoundVar::from_u32(counter),
231-
kind: ty::BrAnon(counter),
232-
};
233-
let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
234-
counter += 1;
235-
r
236-
});
223+
// Replace all regions inside the generator interior with late bound regions.
224+
// Note that each region slot in the types gets a new fresh late bound region,
225+
// which means that none of the regions inside relate to any other, even if
226+
// typeck had previously found constraints that would cause them to be related.
237227

238-
cause.ty = folded;
228+
let mut counter = 0;
229+
let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
230+
let ty = fcx.tcx.fold_regions(ty, |region, current_depth| {
231+
let br = match region.kind() {
232+
ty::ReVar(vid) => {
233+
let origin = fcx.region_var_origin(vid);
234+
match origin {
235+
RegionVariableOrigin::EarlyBoundRegion(span, _) => {
236+
let kind = ty::BrAnon(counter, Some(span));
237+
let var = ty::BoundVar::from_u32(counter);
238+
counter += 1;
239+
ty::BoundRegion { var, kind }
240+
}
241+
_ => {
242+
let kind = ty::BrAnon(counter, None);
243+
let var = ty::BoundVar::from_u32(counter);
244+
counter += 1;
245+
ty::BoundRegion { var, kind }
246+
}
247+
}
248+
}
249+
_ => {
250+
let kind = ty::BrAnon(counter, None);
251+
let var = ty::BoundVar::from_u32(counter);
252+
counter += 1;
253+
ty::BoundRegion { var, kind }
254+
}
255+
};
256+
let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
257+
r
258+
});
259+
if captured_tys.insert(ty) {
260+
cause.ty = ty;
239261
Some(cause)
240262
} else {
241263
None
242264
}
243265
})
244266
.collect();
245267

268+
let mut bound_vars: Vec<BoundVariableKind> = vec![];
269+
let mut counter = 0;
270+
let type_causes = fcx.tcx.fold_regions(type_causes, |region, current_depth| {
271+
let br = match region.kind() {
272+
ty::ReLateBound(_, br) => {
273+
let kind = match br.kind {
274+
ty::BrAnon(_, span) => ty::BrAnon(counter, span),
275+
_ => br.kind,
276+
};
277+
let var = ty::BoundVar::from_usize(bound_vars.len());
278+
bound_vars.push(ty::BoundVariableKind::Region(kind));
279+
counter += 1;
280+
ty::BoundRegion { var, kind }
281+
}
282+
_ => bug!("All regions should have been replaced by ReLateBound"),
283+
};
284+
let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
285+
r
286+
});
287+
246288
// Extract type components to build the witness type.
247289
let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
248-
let bound_vars = fcx.tcx.mk_bound_variable_kinds(
249-
(0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
250-
);
290+
let bound_vars = fcx.tcx.mk_bound_variable_kinds(bound_vars.iter());
251291
let witness =
252292
fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
253293

compiler/rustc_hir_typeck/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
209209
typeck_with_fallback(tcx, def_id, fallback)
210210
}
211211

212+
#[instrument(level = "debug", skip(tcx, fallback), ret)]
212213
fn typeck_with_fallback<'tcx>(
213214
tcx: TyCtxt<'tcx>,
214215
def_id: LocalDefId,

compiler/rustc_infer/src/errors/note_and_explain.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,13 @@ impl<'a> DescriptionCtx<'a> {
8989
};
9090
me.span = Some(sp);
9191
}
92-
ty::BrAnon(idx) => {
92+
ty::BrAnon(idx, span) => {
9393
me.kind = "anon_num_here";
9494
me.num_arg = idx+1;
95-
me.span = Some(tcx.def_span(scope));
95+
me.span = match span {
96+
Some(_) => span,
97+
None => Some(tcx.def_span(scope)),
98+
}
9699
},
97100
_ => {
98101
me.kind = "defined_here_reg";

compiler/rustc_infer/src/infer/canonical/canonicalizer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
738738
r: ty::Region<'tcx>,
739739
) -> ty::Region<'tcx> {
740740
let var = self.canonical_var(info, r.into());
741-
let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32()) };
741+
let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32(), None) };
742742
let region = ty::ReLateBound(self.binder_index, br);
743743
self.tcx().mk_region(region)
744744
}

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,12 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
206206
};
207207
(text, sp)
208208
}
209-
ty::BrAnon(idx) => (
209+
ty::BrAnon(idx, span) => (
210210
format!("the anonymous lifetime #{} defined here", idx + 1),
211-
tcx.def_span(scope)
211+
match span {
212+
Some(span) => span,
213+
None => tcx.def_span(scope)
214+
}
212215
),
213216
_ => (
214217
format!("the lifetime `{}` as defined here", region),

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub mod find_anon_type;
1010
mod mismatched_static_lifetime;
1111
mod named_anon_conflict;
1212
mod placeholder_error;
13+
mod placeholder_relation;
1314
mod static_impl_trait;
1415
mod trait_impl_difference;
1516
mod util;
@@ -52,7 +53,9 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
5253
pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
5354
// Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
5455
// the nice region errors are required when running under the MIR borrow checker.
55-
self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict())
56+
self.try_report_named_anon_conflict()
57+
.or_else(|| self.try_report_placeholder_conflict())
58+
.or_else(|| self.try_report_placeholder_relation())
5659
}
5760

5861
pub fn try_report(&self) -> Option<ErrorGuaranteed> {

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
6868
let is_impl_item = region_info.is_impl_item;
6969

7070
match br {
71-
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
71+
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) => {}
7272
_ => {
7373
/* not an anonymous region */
7474
debug!("try_report_named_anon_conflict: not an anonymous region");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use crate::infer::{
2+
error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin,
3+
};
4+
use rustc_data_structures::intern::Interned;
5+
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
6+
use rustc_middle::ty::{self, RePlaceholder, Region};
7+
8+
impl<'tcx> NiceRegionError<'_, 'tcx> {
9+
/// Emitted wwhen given a `ConcreteFailure` when relating two placeholders.
10+
pub(super) fn try_report_placeholder_relation(
11+
&self,
12+
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
13+
match &self.error {
14+
Some(RegionResolutionError::ConcreteFailure(
15+
SubregionOrigin::RelateRegionParamBound(span),
16+
Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)),
17+
Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
18+
)) => {
19+
let msg = "lifetime bound not satisfied";
20+
let mut err = self.tcx().sess.struct_span_err(*span, msg);
21+
let (sub_span, sub_symbol) = match sub_name {
22+
ty::BrNamed(def_id, symbol) => {
23+
(Some(self.tcx().def_span(def_id)), Some(symbol))
24+
}
25+
ty::BrAnon(_, span) => (*span, None),
26+
ty::BrEnv => (None, None),
27+
};
28+
let (sup_span, sup_symbol) = match sup_name {
29+
ty::BrNamed(def_id, symbol) => {
30+
(Some(self.tcx().def_span(def_id)), Some(symbol))
31+
}
32+
ty::BrAnon(_, span) => (*span, None),
33+
ty::BrEnv => (None, None),
34+
};
35+
match (sub_span, sup_span, sub_symbol, sup_symbol) {
36+
(Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => {
37+
err.span_note(
38+
sub_span,
39+
format!("the lifetime `{sub_symbol}` defined here..."),
40+
);
41+
err.span_note(
42+
sup_span,
43+
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
44+
);
45+
}
46+
(Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
47+
err.span_note(sub_span, format!("the lifetime defined here..."));
48+
err.span_note(
49+
sup_span,
50+
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
51+
);
52+
}
53+
(Some(sub_span), Some(sup_span), Some(sub_symbol), _) => {
54+
err.span_note(
55+
sub_span,
56+
format!("the lifetime `{sub_symbol}` defined here..."),
57+
);
58+
err.span_note(
59+
sup_span,
60+
format!("...must outlive the lifetime defined here"),
61+
);
62+
}
63+
(Some(sub_span), Some(sup_span), _, _) => {
64+
err.span_note(sub_span, format!("the lifetime defined here, ..."));
65+
err.span_note(
66+
sup_span,
67+
format!("...must outlive the lifetime defined here"),
68+
);
69+
}
70+
_ => {}
71+
}
72+
Some(err)
73+
}
74+
75+
_ => None,
76+
}
77+
}
78+
}

compiler/rustc_middle/src/infer/canonical.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,10 @@ impl<'tcx> CanonicalVarValues<'tcx> {
336336
tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
337337
}
338338
GenericArgKind::Lifetime(..) => {
339-
let br =
340-
ty::BoundRegion { var: ty::BoundVar::from_u32(i), kind: ty::BrAnon(i) };
339+
let br = ty::BoundRegion {
340+
var: ty::BoundVar::from_u32(i),
341+
kind: ty::BrAnon(i, None),
342+
};
341343
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
342344
}
343345
GenericArgKind::Const(ct) => tcx

0 commit comments

Comments
 (0)