Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 36c0ee9

Browse files
committedSep 18, 2018
Auto merge of #53900 - davidtwco:issue-53771, r=nikomatsakis
NLL regresses diagnostic for impl-trait/static-return-lifetime-infered.rs Fixes #53771. r? @nikomatsakis cc @pnkfelix @estebank
2 parents b80cb47 + 18c1374 commit 36c0ee9

File tree

11 files changed

+276
-124
lines changed

11 files changed

+276
-124
lines changed
 

‎src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
5656
let (span, sub, sup) = self.get_regions();
5757

5858
// Determine whether the sub and sup consist of both anonymous (elided) regions.
59-
let anon_reg_sup = self.is_suitable_region(sup)?;
59+
let anon_reg_sup = self.tcx.is_suitable_region(sup)?;
6060

61-
let anon_reg_sub = self.is_suitable_region(sub)?;
61+
let anon_reg_sub = self.tcx.is_suitable_region(sub)?;
6262
let scope_def_id_sup = anon_reg_sup.def_id;
6363
let bregion_sup = anon_reg_sup.boundregion;
6464
let scope_def_id_sub = anon_reg_sub.def_id;

‎src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
3636
region: Region<'tcx>,
3737
br: &ty::BoundRegion,
3838
) -> Option<(&hir::Ty, &hir::FnDecl)> {
39-
if let Some(anon_reg) = self.is_suitable_region(region) {
39+
if let Some(anon_reg) = self.tcx.is_suitable_region(region) {
4040
let def_id = anon_reg.def_id;
4141
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
4242
let fndecl = match self.tcx.hir.get(node_id) {

‎src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,23 +33,23 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
3333
// version new_ty of its type where the anonymous region is replaced
3434
// with the named one.//scope_def_id
3535
let (named, anon, anon_arg_info, region_info) = if self.is_named_region(sub)
36-
&& self.is_suitable_region(sup).is_some()
36+
&& self.tcx.is_suitable_region(sup).is_some()
3737
&& self.find_arg_with_region(sup, sub).is_some()
3838
{
3939
(
4040
sub,
4141
sup,
4242
self.find_arg_with_region(sup, sub).unwrap(),
43-
self.is_suitable_region(sup).unwrap(),
43+
self.tcx.is_suitable_region(sup).unwrap(),
4444
)
45-
} else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some()
45+
} else if self.is_named_region(sup) && self.tcx.is_suitable_region(sub).is_some()
4646
&& self.find_arg_with_region(sub, sup).is_some()
4747
{
4848
(
4949
sup,
5050
sub,
5151
self.find_arg_with_region(sub, sup).unwrap(),
52-
self.is_suitable_region(sub).unwrap(),
52+
self.tcx.is_suitable_region(sub).unwrap(),
5353
)
5454
} else {
5555
return None; // inapplicable

‎src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
2727
sup_origin,
2828
sup_r,
2929
) => {
30-
let anon_reg_sup = self.is_suitable_region(sup_r)?;
30+
let anon_reg_sup = self.tcx.is_suitable_region(sup_r)?;
3131
if sub_r == &RegionKind::ReStatic &&
32-
self.is_return_type_impl_trait(anon_reg_sup.def_id)
32+
self.tcx.return_type_impl_trait(anon_reg_sup.def_id).is_some()
3333
{
3434
let sp = var_origin.span();
3535
let return_sp = sub_origin.span();

‎src/librustc/infer/error_reporting/nice_region_error/util.rs

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use hir;
1515
use infer::error_reporting::nice_region_error::NiceRegionError;
1616
use ty::{self, Region, Ty};
1717
use hir::def_id::DefId;
18-
use hir::Node;
1918
use syntax_pos::Span;
2019

2120
// The struct contains the information about the anonymous region
@@ -35,18 +34,6 @@ pub(super) struct AnonymousArgInfo<'tcx> {
3534
pub is_first: bool,
3635
}
3736

38-
// This struct contains information regarding the
39-
// Refree((FreeRegion) corresponding to lifetime conflict
40-
#[derive(Debug)]
41-
pub(super) struct FreeRegionInfo {
42-
// def id corresponding to FreeRegion
43-
pub def_id: DefId,
44-
// the bound region corresponding to FreeRegion
45-
pub boundregion: ty::BoundRegion,
46-
// checks if bound region is in Impl Item
47-
pub is_impl_item: bool,
48-
}
49-
5037
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
5138
// This method walks the Type of the function body arguments using
5239
// `fold_regions()` function and returns the
@@ -122,36 +109,6 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
122109
}
123110
}
124111

125-
// This method returns the DefId and the BoundRegion corresponding to the given region.
126-
pub(super) fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
127-
let (suitable_region_binding_scope, bound_region) = match *region {
128-
ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
129-
ty::ReEarlyBound(ref ebr) => (
130-
self.tcx.parent_def_id(ebr.def_id).unwrap(),
131-
ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
132-
),
133-
_ => return None, // not a free region
134-
};
135-
136-
let node_id = self.tcx
137-
.hir
138-
.as_local_node_id(suitable_region_binding_scope)
139-
.unwrap();
140-
let is_impl_item = match self.tcx.hir.find(node_id) {
141-
Some(Node::Item(..)) | Some(Node::TraitItem(..)) => false,
142-
Some(Node::ImplItem(..)) => {
143-
self.is_bound_region_in_impl_item(suitable_region_binding_scope)
144-
}
145-
_ => return None,
146-
};
147-
148-
return Some(FreeRegionInfo {
149-
def_id: suitable_region_binding_scope,
150-
boundregion: bound_region,
151-
is_impl_item: is_impl_item,
152-
});
153-
}
154-
155112
// Here, we check for the case where the anonymous region
156113
// is in the return type.
157114
// FIXME(#42703) - Need to handle certain cases here.
@@ -176,22 +133,6 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
176133
None
177134
}
178135

179-
pub(super) fn is_return_type_impl_trait(
180-
&self,
181-
scope_def_id: DefId,
182-
) -> bool {
183-
let ret_ty = self.tcx.type_of(scope_def_id);
184-
match ret_ty.sty {
185-
ty::FnDef(_, _) => {
186-
let sig = ret_ty.fn_sig(self.tcx);
187-
let output = self.tcx.erase_late_bound_regions(&sig.output());
188-
return output.is_impl_trait();
189-
}
190-
_ => {}
191-
}
192-
false
193-
}
194-
195136
// Here we check for the case where anonymous region
196137
// corresponds to self and if yes, we display E0312.
197138
// FIXME(#42700) - Need to format self properly to
@@ -203,24 +144,4 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
203144
.map(|i| i.method_has_self_argument) == Some(true)
204145
}
205146

206-
// Here we check if the bound region is in Impl Item.
207-
pub(super) fn is_bound_region_in_impl_item(
208-
&self,
209-
suitable_region_binding_scope: DefId,
210-
) -> bool {
211-
let container_id = self.tcx
212-
.associated_item(suitable_region_binding_scope)
213-
.container
214-
.id();
215-
if self.tcx.impl_trait_ref(container_id).is_some() {
216-
// For now, we do not try to target impls of traits. This is
217-
// because this message is going to suggest that the user
218-
// change the fn signature, but they may not be free to do so,
219-
// since the signature must match the trait.
220-
//
221-
// FIXME(#42706) -- in some cases, we could do better here.
222-
return true;
223-
}
224-
false
225-
}
226147
}

‎src/librustc/ty/context.rs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use session::Session;
1717
use session::config::{BorrowckMode, OutputFilenames};
1818
use session::config::CrateType;
1919
use middle;
20-
use hir::{TraitCandidate, HirId, ItemLocalId};
20+
use hir::{TraitCandidate, HirId, ItemLocalId, Node};
2121
use hir::def::{Def, Export};
2222
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
2323
use hir::map as hir_map;
@@ -872,6 +872,18 @@ impl<'tcx> CommonTypes<'tcx> {
872872
}
873873
}
874874

875+
// This struct contains information regarding the `ReFree(FreeRegion)` corresponding to a lifetime
876+
// conflict.
877+
#[derive(Debug)]
878+
pub struct FreeRegionInfo {
879+
// def id corresponding to FreeRegion
880+
pub def_id: DefId,
881+
// the bound region corresponding to FreeRegion
882+
pub boundregion: ty::BoundRegion,
883+
// checks if bound region is in Impl Item
884+
pub is_impl_item: bool,
885+
}
886+
875887
/// The central data structure of the compiler. It stores references
876888
/// to the various **arenas** and also houses the results of the
877889
/// various **compiler queries** that have been performed. See the
@@ -1571,6 +1583,74 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
15711583
}
15721584
})
15731585
}
1586+
1587+
// This method returns the DefId and the BoundRegion corresponding to the given region.
1588+
pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
1589+
let (suitable_region_binding_scope, bound_region) = match *region {
1590+
ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
1591+
ty::ReEarlyBound(ref ebr) => (
1592+
self.parent_def_id(ebr.def_id).unwrap(),
1593+
ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
1594+
),
1595+
_ => return None, // not a free region
1596+
};
1597+
1598+
let node_id = self.hir
1599+
.as_local_node_id(suitable_region_binding_scope)
1600+
.unwrap();
1601+
let is_impl_item = match self.hir.find(node_id) {
1602+
Some(Node::Item(..)) | Some(Node::TraitItem(..)) => false,
1603+
Some(Node::ImplItem(..)) => {
1604+
self.is_bound_region_in_impl_item(suitable_region_binding_scope)
1605+
}
1606+
_ => return None,
1607+
};
1608+
1609+
return Some(FreeRegionInfo {
1610+
def_id: suitable_region_binding_scope,
1611+
boundregion: bound_region,
1612+
is_impl_item: is_impl_item,
1613+
});
1614+
}
1615+
1616+
pub fn return_type_impl_trait(
1617+
&self,
1618+
scope_def_id: DefId,
1619+
) -> Option<Ty<'tcx>> {
1620+
let ret_ty = self.type_of(scope_def_id);
1621+
match ret_ty.sty {
1622+
ty::FnDef(_, _) => {
1623+
let sig = ret_ty.fn_sig(*self);
1624+
let output = self.erase_late_bound_regions(&sig.output());
1625+
if output.is_impl_trait() {
1626+
Some(output)
1627+
} else {
1628+
None
1629+
}
1630+
}
1631+
_ => None
1632+
}
1633+
}
1634+
1635+
// Here we check if the bound region is in Impl Item.
1636+
pub fn is_bound_region_in_impl_item(
1637+
&self,
1638+
suitable_region_binding_scope: DefId,
1639+
) -> bool {
1640+
let container_id = self.associated_item(suitable_region_binding_scope)
1641+
.container
1642+
.id();
1643+
if self.impl_trait_ref(container_id).is_some() {
1644+
// For now, we do not try to target impls of traits. This is
1645+
// because this message is going to suggest that the user
1646+
// change the fn signature, but they may not be free to do so,
1647+
// since the signature must match the trait.
1648+
//
1649+
// FIXME(#42706) -- in some cases, we could do better here.
1650+
return true;
1651+
}
1652+
false
1653+
}
15741654
}
15751655

15761656
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {

‎src/librustc/ty/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ pub use self::sty::TyKind::*;
8080
pub use self::binding::BindingMode;
8181
pub use self::binding::BindingMode::*;
8282

83-
pub use self::context::{TyCtxt, GlobalArenas, AllArenas, tls, keep_local};
83+
pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, keep_local};
8484
pub use self::context::{Lift, TypeckTables};
8585

8686
pub use self::instance::{Instance, InstanceDef};

‎src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,19 @@ use rustc::hir::def_id::DefId;
1515
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
1616
use rustc::infer::InferCtxt;
1717
use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind};
18-
use rustc::ty::{TyCtxt, RegionVid};
18+
use rustc::ty::{self, TyCtxt, RegionVid};
1919
use rustc_data_structures::indexed_vec::IndexVec;
20-
use rustc_errors::Diagnostic;
20+
use rustc_errors::{Diagnostic, DiagnosticBuilder};
2121
use std::collections::VecDeque;
2222
use std::fmt;
23+
use syntax::symbol::keywords;
2324
use syntax_pos::Span;
2425

2526
mod region_name;
2627
mod var_name;
2728

29+
use self::region_name::RegionName;
30+
2831
/// Constraints that are considered interesting can be categorized to
2932
/// determine why they are interesting. Order of variants indicates
3033
/// sort order of the category, thereby influencing diagnostic output.
@@ -356,9 +359,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
356359
self.universal_regions.is_local_free_region(fr),
357360
self.universal_regions.is_local_free_region(outlived_fr),
358361
);
362+
359363
debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
360364
fr_is_local, outlived_fr_is_local, category);
361-
362365
match (category, fr_is_local, outlived_fr_is_local) {
363366
(ConstraintCategory::Assignment, true, false) |
364367
(ConstraintCategory::CallArgument, true, false) =>
@@ -465,9 +468,93 @@ impl<'tcx> RegionInferenceContext<'tcx> {
465468
},
466469
}
467470

471+
self.add_static_impl_trait_suggestion(
472+
infcx, &mut diag, fr, fr_name, outlived_fr,
473+
);
474+
468475
diag.buffer(errors_buffer);
469476
}
470477

478+
fn add_static_impl_trait_suggestion(
479+
&self,
480+
infcx: &InferCtxt<'_, '_, 'tcx>,
481+
diag: &mut DiagnosticBuilder<'_>,
482+
fr: RegionVid,
483+
// We need to pass `fr_name` - computing it again will label it twice.
484+
fr_name: RegionName,
485+
outlived_fr: RegionVid,
486+
) {
487+
if let (
488+
Some(f),
489+
Some(ty::RegionKind::ReStatic)
490+
) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
491+
if let Some(ty::TyS {
492+
sty: ty::TyKind::Opaque(did, substs),
493+
..
494+
}) = infcx.tcx.is_suitable_region(f)
495+
.map(|r| r.def_id)
496+
.map(|id| infcx.tcx.return_type_impl_trait(id))
497+
.unwrap_or(None)
498+
{
499+
// Check whether or not the impl trait return type is intended to capture
500+
// data with the static lifetime.
501+
//
502+
// eg. check for `impl Trait + 'static` instead of `impl Trait`.
503+
let has_static_predicate = {
504+
let predicates_of = infcx.tcx.predicates_of(*did);
505+
let bounds = predicates_of.instantiate(infcx.tcx, substs);
506+
507+
let mut found = false;
508+
for predicate in bounds.predicates {
509+
if let ty::Predicate::TypeOutlives(binder) = predicate {
510+
if let ty::OutlivesPredicate(
511+
_,
512+
ty::RegionKind::ReStatic
513+
) = binder.skip_binder() {
514+
found = true;
515+
break;
516+
}
517+
}
518+
}
519+
520+
found
521+
};
522+
523+
debug!("add_static_impl_trait_suggestion: has_static_predicate={:?}",
524+
has_static_predicate);
525+
let static_str = keywords::StaticLifetime.name();
526+
// If there is a static predicate, then the only sensible suggestion is to replace
527+
// fr with `'static`.
528+
if has_static_predicate {
529+
diag.help(
530+
&format!(
531+
"consider replacing `{}` with `{}`",
532+
fr_name, static_str,
533+
),
534+
);
535+
} else {
536+
// Otherwise, we should suggest adding a constraint on the return type.
537+
let span = infcx.tcx.def_span(*did);
538+
if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(span) {
539+
let suggestable_fr_name = match fr_name {
540+
RegionName::Named(name) => format!("{}", name),
541+
RegionName::Synthesized(_) => "'_".to_string(),
542+
};
543+
diag.span_suggestion(
544+
span,
545+
&format!(
546+
"to allow this impl Trait to capture borrowed data with lifetime \
547+
`{}`, add `{}` as a constraint",
548+
fr_name, suggestable_fr_name,
549+
),
550+
format!("{} + {}", snippet, suggestable_fr_name),
551+
);
552+
}
553+
}
554+
}
555+
}
556+
}
557+
471558
// Finds some region R such that `fr1: R` and `R` is live at
472559
// `elem`.
473560
crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {

‎src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs

Lines changed: 81 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use std::fmt::{self, Display};
1112
use borrow_check::nll::region_infer::RegionInferenceContext;
1213
use borrow_check::nll::universal_regions::DefiningTy;
1314
use borrow_check::nll::ToRegionVid;
@@ -21,8 +22,35 @@ use rustc::util::ppaux::with_highlight_region;
2122
use rustc_errors::DiagnosticBuilder;
2223
use syntax::ast::{Name, DUMMY_NODE_ID};
2324
use syntax::symbol::keywords;
25+
use syntax_pos::Span;
2426
use syntax_pos::symbol::InternedString;
2527

28+
/// Name of a region used in error reporting. Variants denote the source of the region name -
29+
/// whether it was synthesized for the error message and therefore should not be used in
30+
/// suggestions; or whether it was found from the region.
31+
#[derive(Debug)]
32+
pub(crate) enum RegionName {
33+
Named(InternedString),
34+
Synthesized(InternedString),
35+
}
36+
37+
impl RegionName {
38+
fn as_interned_string(&self) -> &InternedString {
39+
match self {
40+
RegionName::Named(name) | RegionName::Synthesized(name) => name,
41+
}
42+
}
43+
}
44+
45+
impl Display for RegionName {
46+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47+
match self {
48+
RegionName::Named(name) | RegionName::Synthesized(name) =>
49+
write!(f, "{}", name),
50+
}
51+
}
52+
}
53+
2654
impl<'tcx> RegionInferenceContext<'tcx> {
2755
/// Maps from an internal MIR region vid to something that we can
2856
/// report to the user. In some cases, the region vids will map
@@ -57,7 +85,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
5785
fr: RegionVid,
5886
counter: &mut usize,
5987
diag: &mut DiagnosticBuilder,
60-
) -> InternedString {
88+
) -> RegionName {
6189
debug!("give_region_a_name(fr={:?}, counter={})", fr, counter);
6290

6391
assert!(self.universal_regions.is_universal_region(fr));
@@ -95,27 +123,31 @@ impl<'tcx> RegionInferenceContext<'tcx> {
95123
fr: RegionVid,
96124
counter: &mut usize,
97125
diag: &mut DiagnosticBuilder<'_>,
98-
) -> Option<InternedString> {
126+
) -> Option<RegionName> {
99127
let error_region = self.to_error_region(fr)?;
100128

101129
debug!("give_region_a_name: error_region = {:?}", error_region);
102130
match error_region {
103131
ty::ReEarlyBound(ebr) => {
104132
if ebr.has_name() {
105-
self.highlight_named_span(tcx, error_region, &ebr.name, diag);
106-
Some(ebr.name)
133+
let name = RegionName::Named(ebr.name);
134+
self.highlight_named_span(tcx, error_region, &name, diag);
135+
Some(name)
107136
} else {
108137
None
109138
}
110139
}
111140

112-
ty::ReStatic => Some(keywords::StaticLifetime.name().as_interned_str()),
141+
ty::ReStatic => Some(RegionName::Named(
142+
keywords::StaticLifetime.name().as_interned_str()
143+
)),
113144

114145
ty::ReFree(free_region) => match free_region.bound_region {
115146
ty::BoundRegion::BrNamed(_, name) => {
147+
let name = RegionName::Named(name);
116148
self.highlight_named_span(tcx, error_region, &name, diag);
117149
Some(name)
118-
}
150+
},
119151

120152
ty::BoundRegion::BrEnv => {
121153
let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir");
@@ -132,7 +164,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
132164
let region_name = self.synthesize_region_name(counter);
133165
diag.span_label(
134166
args_span,
135-
format!("lifetime `{}` represents this closure's body", region_name),
167+
format!(
168+
"lifetime `{}` represents this closure's body",
169+
region_name
170+
),
136171
);
137172

138173
let closure_kind_ty = substs.closure_kind_ty(def_id, tcx);
@@ -174,6 +209,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
174209
}
175210
}
176211

212+
/// Get the span of a named region.
213+
pub(super) fn get_span_of_named_region(
214+
&self,
215+
tcx: TyCtxt<'_, '_, 'tcx>,
216+
error_region: &RegionKind,
217+
name: &RegionName,
218+
) -> Span {
219+
let scope = error_region.free_region_binding_scope(tcx);
220+
let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
221+
222+
let span = tcx.sess.source_map().def_span(tcx.hir.span(node));
223+
if let Some(param) = tcx.hir.get_generics(scope).and_then(|generics| {
224+
generics.get_named(name.as_interned_string())
225+
}) {
226+
param.span
227+
} else {
228+
span
229+
}
230+
}
231+
177232
/// Highlight a named span to provide context for error messages that
178233
/// mention that span, for example:
179234
///
@@ -192,23 +247,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
192247
&self,
193248
tcx: TyCtxt<'_, '_, 'tcx>,
194249
error_region: &RegionKind,
195-
name: &InternedString,
250+
name: &RegionName,
196251
diag: &mut DiagnosticBuilder<'_>,
197252
) {
198-
let cm = tcx.sess.source_map();
253+
let span = self.get_span_of_named_region(tcx, error_region, name);
199254

200-
let scope = error_region.free_region_binding_scope(tcx);
201-
let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
202-
203-
let mut sp = cm.def_span(tcx.hir.span(node));
204-
if let Some(param) = tcx.hir
205-
.get_generics(scope)
206-
.and_then(|generics| generics.get_named(name))
207-
{
208-
sp = param.span;
209-
}
210-
211-
diag.span_label(sp, format!("lifetime `{}` defined here", name));
255+
diag.span_label(
256+
span,
257+
format!("lifetime `{}` defined here", name),
258+
);
212259
}
213260

214261
/// Find an argument that contains `fr` and label it with a fully
@@ -227,7 +274,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
227274
fr: RegionVid,
228275
counter: &mut usize,
229276
diag: &mut DiagnosticBuilder<'_>,
230-
) -> Option<InternedString> {
277+
) -> Option<RegionName> {
231278
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
232279
let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?;
233280

@@ -259,7 +306,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
259306
argument_index: usize,
260307
counter: &mut usize,
261308
diag: &mut DiagnosticBuilder<'_>,
262-
) -> Option<InternedString> {
309+
) -> Option<RegionName> {
263310
let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id)?;
264311
let fn_decl = infcx.tcx.hir.fn_decl(mir_node_id)?;
265312
let argument_hir_ty: &hir::Ty = &fn_decl.inputs[argument_index];
@@ -306,7 +353,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
306353
argument_ty: Ty<'tcx>,
307354
counter: &mut usize,
308355
diag: &mut DiagnosticBuilder<'_>,
309-
) -> Option<InternedString> {
356+
) -> Option<RegionName> {
310357
let type_name = with_highlight_region(needle_fr, *counter, || {
311358
infcx.extract_type_name(&argument_ty)
312359
});
@@ -361,7 +408,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
361408
argument_hir_ty: &hir::Ty,
362409
counter: &mut usize,
363410
diag: &mut DiagnosticBuilder<'_>,
364-
) -> Option<InternedString> {
411+
) -> Option<RegionName> {
365412
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> = &mut Vec::new();
366413

367414
search_stack.push((argument_ty, argument_hir_ty));
@@ -457,7 +504,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
457504
counter: &mut usize,
458505
diag: &mut DiagnosticBuilder<'_>,
459506
search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
460-
) -> Option<InternedString> {
507+
) -> Option<RegionName> {
461508
// Did the user give explicit arguments? (e.g., `Foo<..>`)
462509
let args = last_segment.args.as_ref()?;
463510
let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
@@ -467,7 +514,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
467514
| hir::LifetimeName::Underscore => {
468515
let region_name = self.synthesize_region_name(counter);
469516
let ampersand_span = lifetime.span;
470-
diag.span_label(ampersand_span, format!("let's call this `{}`", region_name));
517+
diag.span_label(
518+
ampersand_span,
519+
format!("let's call this `{}`", region_name)
520+
);
471521
return Some(region_name);
472522
}
473523

@@ -544,7 +594,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
544594
fr: RegionVid,
545595
counter: &mut usize,
546596
diag: &mut DiagnosticBuilder<'_>,
547-
) -> Option<InternedString> {
597+
) -> Option<RegionName> {
548598
let upvar_index = self.get_upvar_index_for_region(tcx, fr)?;
549599
let (upvar_name, upvar_span) =
550600
self.get_upvar_name_and_span_for_region(tcx, mir, upvar_index);
@@ -573,7 +623,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
573623
fr: RegionVid,
574624
counter: &mut usize,
575625
diag: &mut DiagnosticBuilder<'_>,
576-
) -> Option<InternedString> {
626+
) -> Option<RegionName> {
577627
let tcx = infcx.tcx;
578628

579629
let return_ty = self.universal_regions.unnormalized_output_ty;
@@ -622,10 +672,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
622672

623673
/// Create a synthetic region named `'1`, incrementing the
624674
/// counter.
625-
fn synthesize_region_name(&self, counter: &mut usize) -> InternedString {
675+
fn synthesize_region_name(&self, counter: &mut usize) -> RegionName {
626676
let c = *counter;
627677
*counter += 1;
628678

629-
Name::intern(&format!("'{:?}", c)).as_interned_str()
679+
RegionName::Synthesized(Name::intern(&format!("'{:?}", c)).as_interned_str())
630680
}
631681
}

‎src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@ error: unsatisfied lifetime constraints
1111
|
1212
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
1313
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
14+
help: to allow this impl Trait to capture borrowed data with lifetime `'a`, add `'a` as a constraint
15+
|
16+
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
17+
| ^^^^^^^^^^^^^^
1418

1519
error: unsatisfied lifetime constraints
1620
--> $DIR/must_outlive_least_region_or_bound.rs:22:69
1721
|
1822
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
1923
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
24+
|
25+
= help: consider replacing `'a` with `'static`
2026

2127
error: unsatisfied lifetime constraints
2228
--> $DIR/must_outlive_least_region_or_bound.rs:29:5

‎src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
55
| - let's call the lifetime of this reference `'1`
66
LL | self.x.iter().map(|a| a.0)
77
| ^^^^^^ cast requires that `'1` must outlive `'static`
8+
help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as a constraint
9+
|
10+
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
812

913
error: unsatisfied lifetime constraints
1014
--> $DIR/static-return-lifetime-infered.rs:21:9
@@ -13,6 +17,10 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
1317
| -- lifetime `'a` defined here
1418
LL | self.x.iter().map(|a| a.0)
1519
| ^^^^^^ cast requires that `'a` must outlive `'static`
20+
help: to allow this impl Trait to capture borrowed data with lifetime `'a`, add `'a` as a constraint
21+
|
22+
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1624

1725
error: aborting due to 2 previous errors
1826

0 commit comments

Comments
 (0)
Please sign in to comment.