Skip to content

Commit 9f84345

Browse files
authored
Rollup merge of rust-lang#97023 - cjgillot:uniform-anon, r=estebank
Diagnose anonymous lifetimes errors more uniformly between async and regular fns Async fns and regular fns are desugared differently. For the former, we create a generic parameter at HIR level. For the latter, we just create an anonymous region for typeck. I plan to migrate regular fns to the async fn desugaring. Before that, this PR attempts to merge the diagnostics for both cases. r? `@estebank`
2 parents 5f5a27f + 0cf79d7 commit 9f84345

33 files changed

+620
-194
lines changed

compiler/rustc_borrowck/src/diagnostics/region_name.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -567,15 +567,17 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
567567
let lifetime =
568568
self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
569569
match lifetime.name {
570-
hir::LifetimeName::Param(_)
570+
hir::LifetimeName::Param(hir::ParamName::Plain(_) | hir::ParamName::Error)
571571
| hir::LifetimeName::Error
572-
| hir::LifetimeName::Static
573-
| hir::LifetimeName::Underscore => {
572+
| hir::LifetimeName::Static => {
574573
let lifetime_span = lifetime.span;
575574
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
576575
}
577576

578-
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
577+
hir::LifetimeName::Param(hir::ParamName::Fresh(_))
578+
| hir::LifetimeName::ImplicitObjectLifetimeDefault
579+
| hir::LifetimeName::Implicit
580+
| hir::LifetimeName::Underscore => {
579581
// In this case, the user left off the lifetime; so
580582
// they wrote something like:
581583
//

compiler/rustc_hir/src/hir.rs

+11
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,17 @@ impl LifetimeName {
131131
}
132132
}
133133

134+
pub fn is_anonymous(&self) -> bool {
135+
match *self {
136+
LifetimeName::ImplicitObjectLifetimeDefault
137+
| LifetimeName::Implicit
138+
| LifetimeName::Underscore
139+
| LifetimeName::Param(ParamName::Fresh(_))
140+
| LifetimeName::Error => true,
141+
LifetimeName::Static | LifetimeName::Param(_) => false,
142+
}
143+
}
144+
134145
pub fn is_elided(&self) -> bool {
135146
match self {
136147
LifetimeName::ImplicitObjectLifetimeDefault

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

+36-26
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ use rustc_middle::ty::{
7272
subst::{GenericArgKind, Subst, SubstsRef},
7373
Binder, EarlyBinder, List, Region, Ty, TyCtxt, TypeFoldable,
7474
};
75-
use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
75+
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
7676
use rustc_target::spec::abi;
7777
use std::ops::ControlFlow;
7878
use std::{cmp, fmt, iter};
@@ -161,35 +161,45 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
161161
{
162162
sp = param.span;
163163
}
164-
(format!("the lifetime `{}` as defined here", br.name), sp)
164+
let text = if br.has_name() {
165+
format!("the lifetime `{}` as defined here", br.name)
166+
} else {
167+
format!("the anonymous lifetime as defined here")
168+
};
169+
(text, sp)
165170
}
166-
ty::ReFree(ty::FreeRegion {
167-
bound_region: ty::BoundRegionKind::BrNamed(_, name), ..
168-
}) => {
169-
let mut sp = sm.guess_head_span(tcx.def_span(scope));
170-
if let Some(param) =
171-
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
171+
ty::ReFree(ref fr) => {
172+
if !fr.bound_region.is_named()
173+
&& let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
172174
{
173-
sp = param.span;
174-
}
175-
(format!("the lifetime `{}` as defined here", name), sp)
176-
}
177-
ty::ReFree(ref fr) => match fr.bound_region {
178-
ty::BrAnon(idx) => {
179-
if let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) {
180-
("the anonymous lifetime defined here".to_string(), ty.span)
181-
} else {
182-
(
175+
("the anonymous lifetime defined here".to_string(), ty.span)
176+
} else {
177+
match fr.bound_region {
178+
ty::BoundRegionKind::BrNamed(_, name) => {
179+
let mut sp = sm.guess_head_span(tcx.def_span(scope));
180+
if let Some(param) =
181+
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
182+
{
183+
sp = param.span;
184+
}
185+
let text = if name == kw::UnderscoreLifetime {
186+
format!("the anonymous lifetime as defined here")
187+
} else {
188+
format!("the lifetime `{}` as defined here", name)
189+
};
190+
(text, sp)
191+
}
192+
ty::BrAnon(idx) => (
183193
format!("the anonymous lifetime #{} defined here", idx + 1),
184-
tcx.def_span(scope),
185-
)
194+
tcx.def_span(scope)
195+
),
196+
_ => (
197+
format!("the lifetime `{}` as defined here", region),
198+
sm.guess_head_span(tcx.def_span(scope)),
199+
),
186200
}
187201
}
188-
_ => (
189-
format!("the lifetime `{}` as defined here", region),
190-
sm.guess_head_span(tcx.def_span(scope)),
191-
),
192-
},
202+
}
193203
_ => bug!(),
194204
}
195205
}
@@ -2552,7 +2562,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
25522562
ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
25532563
| ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }),
25542564
_,
2555-
) => {
2565+
) if name != kw::UnderscoreLifetime => {
25562566
// Does the required lifetime have a nice name we can print?
25572567
let mut err = struct_span_err!(
25582568
self.tcx.sess,

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

+28-22
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
1212
use rustc_hir as hir;
1313
use rustc_hir::{GenericParamKind, Ty};
1414
use rustc_middle::ty::Region;
15+
use rustc_span::symbol::kw;
1516

1617
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
1718
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -169,7 +170,7 @@ pub fn suggest_adding_lifetime_params<'tcx>(
169170
return false;
170171
};
171172

172-
if !lifetime_sub.name.is_elided() || !lifetime_sup.name.is_elided() {
173+
if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
173174
return false;
174175
};
175176

@@ -188,32 +189,37 @@ pub fn suggest_adding_lifetime_params<'tcx>(
188189
_ => return false,
189190
};
190191

191-
let (suggestion_param_name, introduce_new) = generics
192+
let suggestion_param_name = generics
192193
.params
193194
.iter()
194-
.find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
195-
.and_then(|p| tcx.sess.source_map().span_to_snippet(p.span).ok())
196-
.map(|name| (name, false))
197-
.unwrap_or_else(|| ("'a".to_string(), true));
198-
199-
let mut suggestions = vec![
200-
if let hir::LifetimeName::Underscore = lifetime_sub.name {
201-
(lifetime_sub.span, suggestion_param_name.clone())
195+
.filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
196+
.map(|p| p.name.ident().name)
197+
.find(|i| *i != kw::UnderscoreLifetime);
198+
let introduce_new = suggestion_param_name.is_none();
199+
let suggestion_param_name =
200+
suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
201+
202+
debug!(?lifetime_sup.span);
203+
debug!(?lifetime_sub.span);
204+
let make_suggestion = |span: rustc_span::Span| {
205+
if span.is_empty() {
206+
(span, format!("{}, ", suggestion_param_name))
207+
} else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() {
208+
(span.shrink_to_hi(), format!("{} ", suggestion_param_name))
202209
} else {
203-
(lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
204-
},
205-
if let hir::LifetimeName::Underscore = lifetime_sup.name {
206-
(lifetime_sup.span, suggestion_param_name.clone())
207-
} else {
208-
(lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
209-
},
210-
];
210+
(span, suggestion_param_name.clone())
211+
}
212+
};
213+
let mut suggestions =
214+
vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
211215

212216
if introduce_new {
213-
let new_param_suggestion = match &generics.params {
214-
[] => (generics.span, format!("<{}>", suggestion_param_name)),
215-
[first, ..] => (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)),
216-
};
217+
let new_param_suggestion =
218+
if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) {
219+
(first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
220+
} else {
221+
(generics.span, format!("<{}>", suggestion_param_name))
222+
};
217223

218224
suggestions.push(new_param_suggestion);
219225
}

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_
44
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
55
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
66
use rustc_middle::ty;
7+
use rustc_span::symbol::kw;
78

89
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
910
/// When given a `ConcreteFailure` for a function with parameters containing a named region and
@@ -67,7 +68,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
6768
let is_impl_item = region_info.is_impl_item;
6869

6970
match br {
70-
ty::BrAnon(_) => {}
71+
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
7172
_ => {
7273
/* not an anonymous region */
7374
debug!("try_report_named_anon_conflict: not an anonymous region");

compiler/rustc_middle/src/ty/print/pretty.rs

+28-43
Original file line numberDiff line numberDiff line change
@@ -2177,61 +2177,47 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
21772177
define_scoped_cx!(self);
21782178

21792179
let mut region_index = self.region_index;
2180+
let mut next_name = |this: &Self| loop {
2181+
let name = name_by_region_index(region_index);
2182+
region_index += 1;
2183+
if !this.used_region_names.contains(&name) {
2184+
break name;
2185+
}
2186+
};
2187+
21802188
// If we want to print verbosely, then print *all* binders, even if they
21812189
// aren't named. Eventually, we might just want this as the default, but
21822190
// this is not *quite* right and changes the ordering of some output
21832191
// anyways.
21842192
let (new_value, map) = if self.tcx().sess.verbose() {
21852193
// anon index + 1 (BrEnv takes 0) -> name
2186-
let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default();
2194+
let mut region_map: FxHashMap<_, _> = Default::default();
21872195
let bound_vars = value.bound_vars();
21882196
for var in bound_vars {
2197+
let ty::BoundVariableKind::Region(var) = var else { continue };
21892198
match var {
2190-
ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => {
2199+
ty::BrAnon(_) | ty::BrEnv => {
21912200
start_or_continue(&mut self, "for<", ", ");
2201+
let name = next_name(&self);
21922202
do_continue(&mut self, name);
2203+
region_map.insert(var, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name));
21932204
}
2194-
ty::BoundVariableKind::Region(ty::BrAnon(i)) => {
2205+
ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
21952206
start_or_continue(&mut self, "for<", ", ");
2196-
let name = loop {
2197-
let name = name_by_region_index(region_index);
2198-
region_index += 1;
2199-
if !self.used_region_names.contains(&name) {
2200-
break name;
2201-
}
2202-
};
2207+
let name = next_name(&self);
22032208
do_continue(&mut self, name);
2204-
region_map.insert(i + 1, name);
2209+
region_map.insert(var, ty::BrNamed(def_id, name));
22052210
}
2206-
ty::BoundVariableKind::Region(ty::BrEnv) => {
2211+
ty::BrNamed(_, name) => {
22072212
start_or_continue(&mut self, "for<", ", ");
2208-
let name = loop {
2209-
let name = name_by_region_index(region_index);
2210-
region_index += 1;
2211-
if !self.used_region_names.contains(&name) {
2212-
break name;
2213-
}
2214-
};
22152213
do_continue(&mut self, name);
2216-
region_map.insert(0, name);
22172214
}
2218-
_ => continue,
22192215
}
22202216
}
22212217
start_or_continue(&mut self, "", "> ");
22222218

22232219
self.tcx.replace_late_bound_regions(value.clone(), |br| {
2224-
let kind = match br.kind {
2225-
ty::BrNamed(_, _) => br.kind,
2226-
ty::BrAnon(i) => {
2227-
let name = region_map[&(i + 1)];
2228-
ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
2229-
}
2230-
ty::BrEnv => {
2231-
let name = region_map[&0];
2232-
ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
2233-
}
2234-
};
2220+
let kind = region_map[&br.kind];
22352221
self.tcx.mk_region(ty::ReLateBound(
22362222
ty::INNERMOST,
22372223
ty::BoundRegion { var: br.var, kind },
@@ -2242,21 +2228,20 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
22422228
let mut name = |br: ty::BoundRegion| {
22432229
start_or_continue(&mut self, "for<", ", ");
22442230
let kind = match br.kind {
2245-
ty::BrNamed(_, name) => {
2246-
do_continue(&mut self, name);
2247-
br.kind
2248-
}
22492231
ty::BrAnon(_) | ty::BrEnv => {
2250-
let name = loop {
2251-
let name = name_by_region_index(region_index);
2252-
region_index += 1;
2253-
if !self.used_region_names.contains(&name) {
2254-
break name;
2255-
}
2256-
};
2232+
let name = next_name(&self);
22572233
do_continue(&mut self, name);
22582234
ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
22592235
}
2236+
ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
2237+
let name = next_name(&self);
2238+
do_continue(&mut self, name);
2239+
ty::BrNamed(def_id, name)
2240+
}
2241+
ty::BrNamed(_, name) => {
2242+
do_continue(&mut self, name);
2243+
br.kind
2244+
}
22602245
};
22612246
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
22622247
};

0 commit comments

Comments
 (0)