Skip to content

Commit ceaef73

Browse files
authored
Rollup merge of #74661 - SNCPlay42:lifetime-names-refactor, r=estebank
Refactor `region_name`: add `RegionNameHighlight` This PR does not change any diagnostics itself, rather it enables further code changes, but I would like to get approval for the refactoring first before making use of it. In `rustc_mir::borrow_check::diagnostics::region_name`, there is code that allows for, when giving a synthesized name like `'1` to an anonymous lifetime, pointing at e.g. the exact '`&`' that introduces the lifetime. This PR decouples that code from the specific case of arguments, adding a new enum `RegionNameHighlight`, enabling future changes to use it in other places. This allows: * We could change the other `AnonRegionFrom*` variants to use `RegionNameHighlight` to precisely point at where lifetimes are introduced in other locations when they have type annotations, e.g. a closure return `|...| -> &i32`. * Because of how async functions are lowered this affects async functions as well, see #74072 * for #74597, we could add a second, optional `RegionNameHighlight` to the `AnonRegionFromArgument` variant that highlights a lifetime in the return type of a function when, due to elision, this is the same as the argument lifetime. * in #74497 (comment) I noticed that a diagnostic was trying to introduce a lifetime `'2` in the opaque type `impl std::future::Future`. The code for the case of arguments has [code to handle cases like this](https://github.com/rust-lang/rust/blob/bbebe7351fcd29af1eb9a35e315369b15887ea09/src/librustc_mir/borrow_check/diagnostics/region_name.rs#L365) but not the others. This refactoring would allow the same code path to handle this. * It might be appropriate to add another variant of `RegionNameHighlight` to say something like `lifetime '1 appears in the opaque type impl std::future::Future`. These are quite a few changes so I thought I would make sure the refactoring is OK before I start making changes that rely on it. :)
2 parents a4024ba + 8a776ee commit ceaef73

File tree

3 files changed

+92
-89
lines changed

3 files changed

+92
-89
lines changed

src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ impl OutlivesSuggestionBuilder {
6060
// Don't give suggestions for upvars, closure return types, or other unnamable
6161
// regions.
6262
RegionNameSource::SynthesizedFreeEnvRegion(..)
63-
| RegionNameSource::CannotMatchHirTy(..)
64-
| RegionNameSource::MatchedHirTy(..)
65-
| RegionNameSource::MatchedAdtAndSegment(..)
63+
| RegionNameSource::AnonRegionFromArgument(..)
6664
| RegionNameSource::AnonRegionFromUpvar(..)
6765
| RegionNameSource::AnonRegionFromOutput(..)
6866
| RegionNameSource::AnonRegionFromYieldTy(..)

src/librustc_mir/borrow_check/diagnostics/region_errors.rs

+3-13
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::borrow_check::{
1919
MirBorrowckCtxt,
2020
};
2121

22-
use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
22+
use super::{OutlivesSuggestionBuilder, RegionName};
2323

2424
impl ConstraintDescription for ConstraintCategory {
2525
fn description(&self) -> &'static str {
@@ -396,18 +396,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
396396
diag.span_label(upvar_span, "variable captured here");
397397
}
398398

399-
match self.give_region_a_name(*outlived_fr).unwrap().source {
400-
RegionNameSource::NamedEarlyBoundRegion(fr_span)
401-
| RegionNameSource::NamedFreeRegion(fr_span)
402-
| RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
403-
| RegionNameSource::CannotMatchHirTy(fr_span, _)
404-
| RegionNameSource::MatchedHirTy(fr_span)
405-
| RegionNameSource::MatchedAdtAndSegment(fr_span)
406-
| RegionNameSource::AnonRegionFromUpvar(fr_span, _)
407-
| RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
408-
diag.span_label(fr_span, "inferred to be a `FnMut` closure");
409-
}
410-
_ => {}
399+
if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
400+
diag.span_label(fr_span, "inferred to be a `FnMut` closure");
411401
}
412402

413403
diag.note(

src/librustc_mir/borrow_check/diagnostics/region_name.rs

+88-73
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,8 @@ crate enum RegionNameSource {
3434
Static,
3535
/// The free region corresponding to the environment of a closure.
3636
SynthesizedFreeEnvRegion(Span, String),
37-
/// The region name corresponds to a region where the type annotation is completely missing
38-
/// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
39-
CannotMatchHirTy(Span, String),
40-
/// The region name corresponds a reference that was found by traversing the type in the HIR.
41-
MatchedHirTy(Span),
42-
/// A region name from the generics list of a struct/enum/union.
43-
MatchedAdtAndSegment(Span),
37+
/// The region corresponding to an argument.
38+
AnonRegionFromArgument(RegionNameHighlight),
4439
/// The region corresponding to a closure upvar.
4540
AnonRegionFromUpvar(Span, String),
4641
/// The region corresponding to the return type of a closure.
@@ -51,23 +46,52 @@ crate enum RegionNameSource {
5146
AnonRegionFromAsyncFn(Span),
5247
}
5348

49+
/// Describes what to highlight to explain to the user that we're giving an anonymous region a
50+
/// synthesized name, and how to highlight it.
51+
#[derive(Debug, Clone)]
52+
crate enum RegionNameHighlight {
53+
/// The anonymous region corresponds to a reference that was found by traversing the type in the HIR.
54+
MatchedHirTy(Span),
55+
/// The anonymous region corresponds to a `'_` in the generics list of a struct/enum/union.
56+
MatchedAdtAndSegment(Span),
57+
/// The anonymous region corresponds to a region where the type annotation is completely missing
58+
/// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
59+
CannotMatchHirTy(Span, String),
60+
}
61+
5462
impl RegionName {
5563
crate fn was_named(&self) -> bool {
5664
match self.source {
5765
RegionNameSource::NamedEarlyBoundRegion(..)
5866
| RegionNameSource::NamedFreeRegion(..)
5967
| RegionNameSource::Static => true,
6068
RegionNameSource::SynthesizedFreeEnvRegion(..)
61-
| RegionNameSource::CannotMatchHirTy(..)
62-
| RegionNameSource::MatchedHirTy(..)
63-
| RegionNameSource::MatchedAdtAndSegment(..)
69+
| RegionNameSource::AnonRegionFromArgument(..)
6470
| RegionNameSource::AnonRegionFromUpvar(..)
6571
| RegionNameSource::AnonRegionFromOutput(..)
6672
| RegionNameSource::AnonRegionFromYieldTy(..)
6773
| RegionNameSource::AnonRegionFromAsyncFn(..) => false,
6874
}
6975
}
7076

77+
crate fn span(&self) -> Option<Span> {
78+
match self.source {
79+
RegionNameSource::Static => None,
80+
RegionNameSource::NamedEarlyBoundRegion(span)
81+
| RegionNameSource::NamedFreeRegion(span)
82+
| RegionNameSource::SynthesizedFreeEnvRegion(span, _)
83+
| RegionNameSource::AnonRegionFromUpvar(span, _)
84+
| RegionNameSource::AnonRegionFromOutput(span, _, _)
85+
| RegionNameSource::AnonRegionFromYieldTy(span, _)
86+
| RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span),
87+
RegionNameSource::AnonRegionFromArgument(ref highlight) => match *highlight {
88+
RegionNameHighlight::MatchedHirTy(span)
89+
| RegionNameHighlight::MatchedAdtAndSegment(span)
90+
| RegionNameHighlight::CannotMatchHirTy(span, _) => Some(span),
91+
},
92+
}
93+
}
94+
7195
crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
7296
match &self.source {
7397
RegionNameSource::NamedFreeRegion(span)
@@ -81,17 +105,22 @@ impl RegionName {
81105
);
82106
diag.note(&note);
83107
}
84-
RegionNameSource::CannotMatchHirTy(span, type_name) => {
108+
RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy(
109+
span,
110+
type_name,
111+
)) => {
85112
diag.span_label(*span, format!("has type `{}`", type_name));
86113
}
87-
RegionNameSource::MatchedHirTy(span)
114+
RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::MatchedHirTy(span))
88115
| RegionNameSource::AnonRegionFromAsyncFn(span) => {
89116
diag.span_label(
90117
*span,
91118
format!("let's call the lifetime of this reference `{}`", self),
92119
);
93120
}
94-
RegionNameSource::MatchedAdtAndSegment(span) => {
121+
RegionNameSource::AnonRegionFromArgument(
122+
RegionNameHighlight::MatchedAdtAndSegment(span),
123+
) => {
95124
diag.span_label(*span, format!("let's call this `{}`", self));
96125
}
97126
RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
@@ -307,21 +336,31 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
307336

308337
let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys
309338
[implicit_inputs + argument_index];
310-
if let Some(region_name) =
311-
self.give_name_if_we_can_match_hir_ty_from_argument(fr, arg_ty, argument_index)
312-
{
313-
return Some(region_name);
314-
}
339+
let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
340+
&self.body,
341+
&self.local_names,
342+
argument_index,
343+
);
315344

316-
self.give_name_if_we_cannot_match_hir_ty(fr, arg_ty)
345+
self.get_argument_hir_ty_for_highlighting(argument_index)
346+
.and_then(|arg_hir_ty| self.highlight_if_we_can_match_hir_ty(fr, arg_ty, arg_hir_ty))
347+
.or_else(|| {
348+
// `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to
349+
// the anonymous region. If it succeeds, the `synthesize_region_name` call below
350+
// will increment the counter, "reserving" the number we just used.
351+
let counter = *self.next_region_name.try_borrow().unwrap();
352+
self.highlight_if_we_cannot_match_hir_ty(fr, arg_ty, span, counter)
353+
})
354+
.map(|highlight| RegionName {
355+
name: self.synthesize_region_name(),
356+
source: RegionNameSource::AnonRegionFromArgument(highlight),
357+
})
317358
}
318359

319-
fn give_name_if_we_can_match_hir_ty_from_argument(
360+
fn get_argument_hir_ty_for_highlighting(
320361
&self,
321-
needle_fr: RegionVid,
322-
argument_ty: Ty<'tcx>,
323362
argument_index: usize,
324-
) -> Option<RegionName> {
363+
) -> Option<&hir::Ty<'tcx>> {
325364
let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
326365
let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
327366
let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
@@ -333,7 +372,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
333372
// (`give_name_if_anonymous_region_appears_in_arguments`).
334373
hir::TyKind::Infer => None,
335374

336-
_ => self.give_name_if_we_can_match_hir_ty(needle_fr, argument_ty, argument_hir_ty),
375+
_ => Some(argument_hir_ty),
337376
}
338377
}
339378

@@ -348,42 +387,28 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
348387
/// | | has type `&'1 u32`
349388
/// | has type `&'2 u32`
350389
/// ```
351-
fn give_name_if_we_cannot_match_hir_ty(
390+
fn highlight_if_we_cannot_match_hir_ty(
352391
&self,
353392
needle_fr: RegionVid,
354-
argument_ty: Ty<'tcx>,
355-
) -> Option<RegionName> {
356-
let counter = *self.next_region_name.try_borrow().unwrap();
393+
ty: Ty<'tcx>,
394+
span: Span,
395+
counter: usize,
396+
) -> Option<RegionNameHighlight> {
357397
let mut highlight = RegionHighlightMode::default();
358398
highlight.highlighting_region_vid(needle_fr, counter);
359-
let type_name = self.infcx.extract_type_name(&argument_ty, Some(highlight)).0;
399+
let type_name = self.infcx.extract_type_name(&ty, Some(highlight)).0;
360400

361401
debug!(
362-
"give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
402+
"highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
363403
type_name, needle_fr
364404
);
365-
let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
405+
if type_name.find(&format!("'{}", counter)).is_some() {
366406
// Only add a label if we can confirm that a region was labelled.
367-
let argument_index =
368-
self.regioncx.get_argument_index_for_region(self.infcx.tcx, needle_fr)?;
369-
let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
370-
&self.body,
371-
&self.local_names,
372-
argument_index,
373-
);
374-
375-
Some(RegionName {
376-
// This counter value will already have been used, so this function will increment
377-
// it so the next value will be used next and return the region name that would
378-
// have been used.
379-
name: self.synthesize_region_name(),
380-
source: RegionNameSource::CannotMatchHirTy(span, type_name),
381-
})
407+
408+
Some(RegionNameHighlight::CannotMatchHirTy(span, type_name))
382409
} else {
383410
None
384-
};
385-
386-
assigned_region_name
411+
}
387412
}
388413

389414
/// Attempts to highlight the specific part of a type annotation
@@ -395,9 +420,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
395420
/// | - let's call the lifetime of this reference `'1`
396421
/// ```
397422
///
398-
/// the way this works is that we match up `argument_ty`, which is
423+
/// the way this works is that we match up `ty`, which is
399424
/// a `Ty<'tcx>` (the internal form of the type) with
400-
/// `argument_hir_ty`, a `hir::Ty` (the syntax of the type
425+
/// `hir_ty`, a `hir::Ty` (the syntax of the type
401426
/// annotation). We are descending through the types stepwise,
402427
/// looking in to find the region `needle_fr` in the internal
403428
/// type. Once we find that, we can use the span of the `hir::Ty`
@@ -407,18 +432,17 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
407432
/// keep track of the **closest** type we've found. If we fail to
408433
/// find the exact `&` or `'_` to highlight, then we may fall back
409434
/// to highlighting that closest type instead.
410-
fn give_name_if_we_can_match_hir_ty(
435+
fn highlight_if_we_can_match_hir_ty(
411436
&self,
412437
needle_fr: RegionVid,
413-
argument_ty: Ty<'tcx>,
414-
argument_hir_ty: &hir::Ty<'_>,
415-
) -> Option<RegionName> {
416-
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> =
417-
&mut vec![(argument_ty, argument_hir_ty)];
438+
ty: Ty<'tcx>,
439+
hir_ty: &hir::Ty<'_>,
440+
) -> Option<RegionNameHighlight> {
441+
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> = &mut vec![(ty, hir_ty)];
418442

419443
while let Some((ty, hir_ty)) = search_stack.pop() {
420444
match (&ty.kind, &hir_ty.kind) {
421-
// Check if the `argument_ty` is `&'X ..` where `'X`
445+
// Check if the `ty` is `&'X ..` where `'X`
422446
// is the region we are looking for -- if so, and we have a `&T`
423447
// on the RHS, then we want to highlight the `&` like so:
424448
//
@@ -429,16 +453,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
429453
hir::TyKind::Rptr(_lifetime, referent_hir_ty),
430454
) => {
431455
if region.to_region_vid() == needle_fr {
432-
let region_name = self.synthesize_region_name();
433-
434456
// Just grab the first character, the `&`.
435457
let source_map = self.infcx.tcx.sess.source_map();
436458
let ampersand_span = source_map.start_point(hir_ty.span);
437459

438-
return Some(RegionName {
439-
name: region_name,
440-
source: RegionNameSource::MatchedHirTy(ampersand_span),
441-
});
460+
return Some(RegionNameHighlight::MatchedHirTy(ampersand_span));
442461
}
443462

444463
// Otherwise, let's descend into the referent types.
@@ -458,13 +477,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
458477
Res::Def(DefKind::TyAlias, _) => (),
459478
_ => {
460479
if let Some(last_segment) = path.segments.last() {
461-
if let Some(name) = self.match_adt_and_segment(
480+
if let Some(highlight) = self.match_adt_and_segment(
462481
substs,
463482
needle_fr,
464483
last_segment,
465484
search_stack,
466485
) {
467-
return Some(name);
486+
return Some(highlight);
468487
}
469488
}
470489
}
@@ -507,7 +526,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
507526
needle_fr: RegionVid,
508527
last_segment: &'hir hir::PathSegment<'hir>,
509528
search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>,
510-
) -> Option<RegionName> {
529+
) -> Option<RegionNameHighlight> {
511530
// Did the user give explicit arguments? (e.g., `Foo<..>`)
512531
let args = last_segment.args.as_ref()?;
513532
let lifetime =
@@ -517,12 +536,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
517536
| hir::LifetimeName::Error
518537
| hir::LifetimeName::Static
519538
| hir::LifetimeName::Underscore => {
520-
let region_name = self.synthesize_region_name();
521-
let ampersand_span = lifetime.span;
522-
Some(RegionName {
523-
name: region_name,
524-
source: RegionNameSource::MatchedAdtAndSegment(ampersand_span),
525-
})
539+
let lifetime_span = lifetime.span;
540+
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
526541
}
527542

528543
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {

0 commit comments

Comments
 (0)