Skip to content

Commit e0e9b21

Browse files
committed
Mugrate mismatched_static_lifetime.rs
1 parent af3343a commit e0e9b21

File tree

4 files changed

+303
-20
lines changed

4 files changed

+303
-20
lines changed

compiler/rustc_error_messages/locales/en-US/infer.ftl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,34 @@ infer_lifetime_param_suggestion = consider introducing a named lifetime paramete
137137
*[false] {""}
138138
}
139139
infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
140+
141+
infer_region_explanation = {$pref_kind ->
142+
*[should_not_happen] [{$pref_kind}]
143+
[empty] {""}
144+
}{$pref_kind ->
145+
[empty] {""}
146+
*[other] {" "}
147+
}{$desc_kind ->
148+
*[should_not_happen] [{$desc_kind}]
149+
[restatic] the static lifetime
150+
[reempty] the empty lifetime
151+
[reemptyuni] the empty lifetime in universe {$desc_arg}
152+
[revar] lifetime {$desc_arg}
153+
154+
[as_defined] the lifetime `{$desc_arg}` as defined here
155+
[as_defined_anon] the anonymous lifetime as defined here
156+
[defined_here] the anonymous lifetime defined here
157+
[anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here
158+
[defined_here_reg] the lifetime `{$desc_arg}` as defined here
159+
}{$suff_kind ->
160+
*[should_not_happen] [{$suff_kind}]
161+
[empty]{""}
162+
[continues] ...
163+
}
164+
165+
infer_mismatched_static_lifetime = incompatible lifetime on type
166+
infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
167+
infer_msl_introduces_static = introduces a `'static` lifetime requirement
168+
infer_msl_unmet_req = because this has an unmet lifetime requirement
169+
infer_msl_trait_note = this has an implicit `'static` lifetime requirement
170+
infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement

compiler/rustc_infer/src/errors.rs renamed to compiler/rustc_infer/src/errors/mod.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use crate::infer::error_reporting::{
1414
ObligationCauseAsDiagArg,
1515
};
1616

17+
pub mod note_and_explain;
18+
1719
#[derive(SessionDiagnostic)]
1820
#[diag(infer::opaque_hidden_type)]
1921
pub struct OpaqueHiddenTypeDiag {
@@ -419,3 +421,69 @@ pub struct LifetimeMismatch<'a> {
419421
#[subdiagnostic]
420422
pub suggestion: AddLifetimeParamsSuggestion<'a>,
421423
}
424+
425+
pub mod mismatched_static_lifetime {
426+
use rustc_errors::{self, fluent, AddSubdiagnostic, MultiSpan};
427+
use rustc_span::Span;
428+
429+
use super::note_and_explain;
430+
431+
pub struct LabeledMultiSpan {
432+
pub multi_span: MultiSpan,
433+
pub binding_span: Span,
434+
}
435+
436+
impl AddSubdiagnostic for LabeledMultiSpan {
437+
fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) {
438+
self.multi_span
439+
.push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
440+
diag.span_note(self.multi_span, fluent::infer::msl_unmet_req);
441+
}
442+
}
443+
444+
pub struct ImplNote {
445+
pub impl_span: Option<Span>,
446+
}
447+
448+
impl AddSubdiagnostic for ImplNote {
449+
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
450+
match self.impl_span {
451+
Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
452+
None => diag.note(fluent::infer::msl_impl_note),
453+
};
454+
}
455+
}
456+
457+
#[derive(SessionSubdiagnostic)]
458+
pub enum TraitSubdiag {
459+
#[note(infer::msl_trait_note)]
460+
Note {
461+
#[primary_span]
462+
span: Span,
463+
},
464+
#[suggestion_verbose(
465+
infer::msl_trait_sugg,
466+
code = " + '_",
467+
applicability = "maybe-incorrect"
468+
)]
469+
Sugg {
470+
#[primary_span]
471+
span: Span,
472+
},
473+
}
474+
475+
#[derive(SessionDiagnostic)]
476+
#[diag(infer::mismatched_static_lifetime)]
477+
pub struct MismatchedStaticLifetime<'a> {
478+
#[primary_span]
479+
pub cause_span: Span,
480+
#[subdiagnostic]
481+
pub multispan_subdiag: LabeledMultiSpan,
482+
#[subdiagnostic]
483+
pub expl: Option<note_and_explain::RegionExplanation<'a>>,
484+
#[subdiagnostic]
485+
pub impl_note: ImplNote,
486+
#[subdiagnostic]
487+
pub trait_subdiags: Vec<TraitSubdiag>,
488+
}
489+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
use crate::infer::error_reporting::nice_region_error::find_anon_type;
2+
use rustc_errors::{self, fluent, AddSubdiagnostic};
3+
use rustc_middle::ty::{self, TyCtxt};
4+
use rustc_span::{symbol::kw, Span};
5+
6+
#[derive(Default)]
7+
struct DescriptionCtx<'a> {
8+
span: Option<Span>,
9+
kind: &'a str,
10+
arg: String,
11+
num_arg: u32,
12+
}
13+
14+
impl<'a> DescriptionCtx<'a> {
15+
fn new<'tcx>(
16+
tcx: TyCtxt<'tcx>,
17+
region: ty::Region<'tcx>,
18+
alt_span: Option<Span>,
19+
) -> Option<Self> {
20+
let mut me = DescriptionCtx::default();
21+
me.span = alt_span;
22+
match *region {
23+
ty::ReEarlyBound(_) | ty::ReFree(_) => {
24+
return Self::from_early_bound_and_free_regions(tcx, region);
25+
}
26+
ty::ReStatic => {
27+
me.kind = "restatic";
28+
}
29+
30+
ty::ReEmpty(ty::UniverseIndex::ROOT) => me.kind = "reempty",
31+
32+
// uh oh, hope no user ever sees THIS
33+
ty::ReEmpty(ui) => {
34+
me.kind = "reemptyuni";
35+
me.arg = format!("{:?}", ui);
36+
}
37+
38+
ty::RePlaceholder(_) => return None,
39+
40+
// FIXME(#13998) RePlaceholder should probably print like
41+
// ReFree rather than dumping Debug output on the user.
42+
//
43+
// We shouldn't really be having unification failures with ReVar
44+
// and ReLateBound though.
45+
ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
46+
me.kind = "revar";
47+
me.arg = format!("{:?}", region);
48+
}
49+
};
50+
Some(me)
51+
}
52+
53+
fn from_early_bound_and_free_regions<'tcx>(
54+
tcx: TyCtxt<'tcx>,
55+
region: ty::Region<'tcx>,
56+
) -> Option<Self> {
57+
let mut me = DescriptionCtx::default();
58+
let scope = region.free_region_binding_scope(tcx).expect_local();
59+
match *region {
60+
ty::ReEarlyBound(ref br) => {
61+
let mut sp = tcx.def_span(scope);
62+
if let Some(param) =
63+
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
64+
{
65+
sp = param.span;
66+
}
67+
if br.has_name() {
68+
me.kind = "as_defined";
69+
me.arg = br.name.to_string();
70+
} else {
71+
me.kind = "as_defined_anon";
72+
};
73+
me.span = Some(sp)
74+
}
75+
ty::ReFree(ref fr) => {
76+
if !fr.bound_region.is_named()
77+
&& let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
78+
{
79+
me.kind = "defined_here";
80+
me.span = Some(ty.span);
81+
} else {
82+
match fr.bound_region {
83+
ty::BoundRegionKind::BrNamed(_, name) => {
84+
let mut sp = tcx.def_span(scope);
85+
if let Some(param) =
86+
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
87+
{
88+
sp = param.span;
89+
}
90+
if name == kw::UnderscoreLifetime {
91+
me.kind = "as_defined_anon";
92+
} else {
93+
me.kind = "as_defined";
94+
me.arg = name.to_string();
95+
};
96+
me.span = Some(sp);
97+
}
98+
ty::BrAnon(idx) => {
99+
me.kind = "anon_num_here";
100+
me.num_arg = idx+1;
101+
me.span = Some(tcx.def_span(scope));
102+
},
103+
_ => {
104+
me.kind = "defined_here_reg";
105+
me.arg = region.to_string();
106+
me.span = Some(tcx.def_span(scope));
107+
},
108+
}
109+
}
110+
}
111+
_ => bug!(),
112+
}
113+
Some(me)
114+
}
115+
116+
fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
117+
diag.set_arg("desc_kind", self.kind);
118+
diag.set_arg("desc_arg", self.arg);
119+
diag.set_arg("desc_num_arg", self.num_arg);
120+
}
121+
}
122+
123+
pub enum PrefixKind {
124+
Empty,
125+
}
126+
127+
pub enum SuffixKind {
128+
Continues,
129+
}
130+
131+
impl PrefixKind {
132+
fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
133+
match self {
134+
Self::Empty => diag.set_arg("pref_kind", "empty"),
135+
};
136+
}
137+
}
138+
139+
impl SuffixKind {
140+
fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
141+
match self {
142+
Self::Continues => diag.set_arg("suff_kind", "continues"),
143+
};
144+
}
145+
}
146+
147+
pub struct RegionExplanation<'a> {
148+
desc: DescriptionCtx<'a>,
149+
prefix: PrefixKind,
150+
suffix: SuffixKind,
151+
}
152+
153+
impl RegionExplanation<'_> {
154+
pub fn new<'tcx>(
155+
tcx: TyCtxt<'tcx>,
156+
region: ty::Region<'tcx>,
157+
alt_span: Option<Span>,
158+
prefix: PrefixKind,
159+
suffix: SuffixKind,
160+
) -> Option<Self> {
161+
Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
162+
}
163+
}
164+
165+
impl AddSubdiagnostic for RegionExplanation<'_> {
166+
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
167+
if let Some(span) = self.desc.span {
168+
diag.span_note(span, fluent::infer::region_explanation);
169+
} else {
170+
diag.note(fluent::infer::region_explanation);
171+
}
172+
self.desc.add_to(diag);
173+
self.prefix.add_to(diag);
174+
self.suffix.add_to(diag);
175+
}
176+
}

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

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
//! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
22
//! to hold.
33
4+
use crate::errors::mismatched_static_lifetime::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
5+
use crate::errors::{mismatched_static_lifetime::LabeledMultiSpan, note_and_explain};
46
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
5-
use crate::infer::error_reporting::note_and_explain_region;
67
use crate::infer::lexical_region_resolve::RegionResolutionError;
78
use crate::infer::{SubregionOrigin, TypeTrace};
89
use crate::traits::ObligationCauseCode;
910
use rustc_data_structures::fx::FxHashSet;
10-
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
11+
use rustc_errors::{ErrorGuaranteed, MultiSpan};
1112
use rustc_hir as hir;
1213
use rustc_hir::intravisit::Visitor;
1314
use rustc_middle::ty::TypeVisitor;
@@ -39,12 +40,20 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
3940
= *parent.code() else {
4041
return None;
4142
};
42-
let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");
43+
4344
// FIXME: we should point at the lifetime
44-
let mut multi_span: MultiSpan = vec![binding_span].into();
45-
multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement");
46-
err.span_note(multi_span, "because this has an unmet lifetime requirement");
47-
note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
45+
let multi_span: MultiSpan = vec![binding_span].into();
46+
let multispan_subdiag = LabeledMultiSpan { multi_span, binding_span };
47+
48+
let expl = note_and_explain::RegionExplanation::new(
49+
self.tcx(),
50+
sup,
51+
Some(binding_span),
52+
note_and_explain::PrefixKind::Empty,
53+
note_and_explain::SuffixKind::Continues,
54+
);
55+
let mut impl_span = None;
56+
let mut trait_subdiags = Vec::new();
4857
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
4958
// If an impl is local, then maybe this isn't what they want. Try to
5059
// be as helpful as possible with implicit lifetimes.
@@ -73,31 +82,30 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
7382
// there aren't trait objects or because none are implicit, then just
7483
// write a single note on the impl itself.
7584

76-
let impl_span = self.tcx().def_span(*impl_def_id);
77-
err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
85+
impl_span = Some(self.tcx().def_span(*impl_def_id));
7886
} else {
7987
// Otherwise, point at all implicit static lifetimes
8088

81-
err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
8289
for span in &traits {
83-
err.span_note(*span, "this has an implicit `'static` lifetime requirement");
90+
trait_subdiags.push(TraitSubdiag::Note { span: *span });
8491
// It would be nice to put this immediately under the above note, but they get
8592
// pushed to the end.
86-
err.span_suggestion_verbose(
87-
span.shrink_to_hi(),
88-
"consider relaxing the implicit `'static` requirement",
89-
" + '_",
90-
Applicability::MaybeIncorrect,
91-
);
93+
trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
9294
}
9395
}
9496
} else {
9597
// Otherwise just point out the impl.
9698

97-
let impl_span = self.tcx().def_span(*impl_def_id);
98-
err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
99+
impl_span = Some(self.tcx().def_span(*impl_def_id));
99100
}
100-
let reported = err.emit();
101+
let err = MismatchedStaticLifetime {
102+
cause_span: cause.span,
103+
multispan_subdiag,
104+
expl,
105+
impl_note: ImplNote { impl_span },
106+
trait_subdiags,
107+
};
108+
let reported = self.tcx().sess.emit_err(err);
101109
Some(reported)
102110
}
103111
}

0 commit comments

Comments
 (0)