Skip to content

Commit bc2504a

Browse files
committed
Auto merge of rust-lang#103171 - jackh726:gen-interior-hrtb-error, r=cjgillot
Better error for HRTB error from generator interior cc rust-lang#100013 This is just a first pass at an error. It could be better, and shouldn't really be emitted in the first place. But this is better than what was being emitted before.
2 parents 8d36948 + 3c71faf commit bc2504a

File tree

23 files changed

+344
-63
lines changed

23 files changed

+344
-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
@@ -2980,15 +2980,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
29802980
) {
29812981
for br in referenced_regions.difference(&constrained_regions) {
29822982
let br_name = match *br {
2983-
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => {
2983+
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => {
29842984
"an anonymous lifetime".to_string()
29852985
}
29862986
ty::BrNamed(_, name) => format!("lifetime `{}`", name),
29872987
};
29882988

29892989
let mut err = generate_err(&br_name);
29902990

2991-
if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br {
2991+
if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) = *br {
29922992
// The only way for an anonymous lifetime to wind up
29932993
// in the return type but **also** be unconstrained is
29942994
// 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

+80-24
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@ 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::fold::FnMutDelegate;
19+
use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitable};
1820
use rustc_span::symbol::sym;
1921
use rustc_span::Span;
22+
use smallvec::{smallvec, SmallVec};
2023

2124
mod drop_ranges;
2225

@@ -211,43 +214,96 @@ pub fn resolve_interior<'a, 'tcx>(
211214

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

214-
let mut counter = 0;
217+
// We want to deduplicate if the lifetimes are the same modulo some non-informative counter.
218+
// So, we need to actually do two passes: first by type to anonymize (preserving information
219+
// required for diagnostics), then a second pass over all captured types to reassign disjoint
220+
// region indices.
215221
let mut captured_tys = FxHashSet::default();
216222
let type_causes: Vec<_> = types
217223
.into_iter()
218224
.filter_map(|mut cause| {
219-
// Erase regions and canonicalize late-bound regions to deduplicate as many types as we
220-
// can.
225+
// Replace all regions inside the generator interior with late bound regions.
226+
// Note that each region slot in the types gets a new fresh late bound region,
227+
// which means that none of the regions inside relate to any other, even if
228+
// typeck had previously found constraints that would cause them to be related.
229+
230+
let mut counter = 0;
231+
let mut mk_bound_region = |span| {
232+
let kind = ty::BrAnon(counter, span);
233+
let var = ty::BoundVar::from_u32(counter);
234+
counter += 1;
235+
ty::BoundRegion { var, kind }
236+
};
221237
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-
});
237-
238-
cause.ty = folded;
238+
let ty = fcx.tcx.fold_regions(ty, |region, current_depth| {
239+
let br = match region.kind() {
240+
ty::ReVar(vid) => {
241+
let origin = fcx.region_var_origin(vid);
242+
match origin {
243+
RegionVariableOrigin::EarlyBoundRegion(span, _) => {
244+
mk_bound_region(Some(span))
245+
}
246+
_ => mk_bound_region(None),
247+
}
248+
}
249+
// FIXME: these should use `BrNamed`
250+
ty::ReEarlyBound(region) => {
251+
mk_bound_region(Some(fcx.tcx.def_span(region.def_id)))
252+
}
253+
ty::ReLateBound(_, ty::BoundRegion { kind, .. })
254+
| ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind {
255+
ty::BoundRegionKind::BrAnon(_, span) => mk_bound_region(span),
256+
ty::BoundRegionKind::BrNamed(def_id, _) => {
257+
mk_bound_region(Some(fcx.tcx.def_span(def_id)))
258+
}
259+
ty::BoundRegionKind::BrEnv => mk_bound_region(None),
260+
},
261+
_ => mk_bound_region(None),
262+
};
263+
let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
264+
r
265+
});
266+
if captured_tys.insert(ty) {
267+
cause.ty = ty;
239268
Some(cause)
240269
} else {
241270
None
242271
}
243272
})
244273
.collect();
245274

275+
let mut bound_vars: SmallVec<[BoundVariableKind; 4]> = smallvec![];
276+
let mut counter = 0;
277+
// Optimization: If there is only one captured type, then we don't actually
278+
// need to fold and reindex (since the first type doesn't change).
279+
let type_causes = if captured_tys.len() > 0 {
280+
// Optimization: Use `replace_escaping_bound_vars_uncached` instead of
281+
// `fold_regions`, since we only have late bound regions, and it skips
282+
// types without bound regions.
283+
fcx.tcx.replace_escaping_bound_vars_uncached(
284+
type_causes,
285+
FnMutDelegate {
286+
regions: &mut |br| {
287+
let kind = match br.kind {
288+
ty::BrAnon(_, span) => ty::BrAnon(counter, span),
289+
_ => br.kind,
290+
};
291+
let var = ty::BoundVar::from_usize(bound_vars.len());
292+
bound_vars.push(ty::BoundVariableKind::Region(kind));
293+
counter += 1;
294+
fcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var, kind }))
295+
},
296+
types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"),
297+
consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"),
298+
},
299+
)
300+
} else {
301+
type_causes
302+
};
303+
246304
// Extract type components to build the witness type.
247305
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-
);
306+
let bound_vars = fcx.tcx.mk_bound_variable_kinds(bound_vars.iter());
251307
let witness =
252308
fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
253309

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
@@ -207,9 +207,12 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
207207
};
208208
(text, sp)
209209
}
210-
ty::BrAnon(idx) => (
210+
ty::BrAnon(idx, span) => (
211211
format!("the anonymous lifetime #{} defined here", idx + 1),
212-
tcx.def_span(scope)
212+
match span {
213+
Some(span) => span,
214+
None => tcx.def_span(scope)
215+
}
213216
),
214217
_ => (
215218
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,79 @@
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+
err.note("this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)");
73+
Some(err)
74+
}
75+
76+
_ => None,
77+
}
78+
}
79+
}

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)