Skip to content

Commit 6bf131f

Browse files
committed
Added help message for impl trait static constraint.
1 parent 78b2164 commit 6bf131f

File tree

5 files changed

+73
-15
lines changed

5 files changed

+73
-15
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
2929
) => {
3030
let anon_reg_sup = self.tcx.is_suitable_region(sup_r)?;
3131
if sub_r == &RegionKind::ReStatic &&
32-
self.tcx.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/ty/context.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,20 +1587,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
15871587
});
15881588
}
15891589

1590-
pub fn is_return_type_impl_trait(
1590+
pub fn return_type_impl_trait(
15911591
&self,
15921592
scope_def_id: DefId,
1593-
) -> bool {
1593+
) -> Option<Ty> {
15941594
let ret_ty = self.type_of(scope_def_id);
15951595
match ret_ty.sty {
15961596
ty::FnDef(_, _) => {
15971597
let sig = ret_ty.fn_sig(*self);
15981598
let output = self.erase_late_bound_regions(&sig.output());
1599-
return output.is_impl_trait();
1599+
if output.is_impl_trait() {
1600+
Some(output)
1601+
} else {
1602+
None
1603+
}
16001604
}
1601-
_ => {}
1605+
_ => None
16021606
}
1603-
false
16041607
}
16051608

16061609
// Here we check if the bound region is in Impl Item.

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

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ 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::{TyCtxt, Ty, TyS, TyKind, Region, RegionKind, RegionVid};
1919
use rustc_data_structures::indexed_vec::IndexVec;
2020
use rustc_errors::Diagnostic;
2121
use std::collections::VecDeque;
@@ -344,7 +344,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
344344
);
345345

346346
// Check if we can use one of the "nice region errors".
347-
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
347+
let fr_region = self.to_error_region(fr);
348+
let outlived_fr_region = self.to_error_region(outlived_fr);
349+
if let (Some(f), Some(o)) = (fr_region, outlived_fr_region) {
348350
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
349351
let nice = NiceRegionError::new_from_span(infcx.tcx, span, o, f, Some(tables));
350352
if let Some(_error_reported) = nice.try_report_from_nll() {
@@ -356,17 +358,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
356358
self.universal_regions.is_local_free_region(fr),
357359
self.universal_regions.is_local_free_region(outlived_fr),
358360
);
359-
debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
360-
fr_is_local, outlived_fr_is_local, category);
361361

362+
debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} fr_region={:?} \
363+
outlived_fr_region={:?} category={:?}",
364+
fr_is_local, outlived_fr_is_local, fr_region, outlived_fr_region, category);
362365
match (category, fr_is_local, outlived_fr_is_local) {
363366
(ConstraintCategory::Assignment, true, false) |
364367
(ConstraintCategory::CallArgument, true, false) =>
365-
self.report_escaping_data_error(mir, infcx, mir_def_id, fr, outlived_fr,
366-
category, span, errors_buffer),
368+
self.report_escaping_data_error(mir, infcx, mir_def_id, fr, fr_region, outlived_fr,
369+
outlived_fr_region, category, span, errors_buffer),
367370
_ =>
368-
self.report_general_error(mir, infcx, mir_def_id, fr, fr_is_local,
369-
outlived_fr, outlived_fr_is_local,
371+
self.report_general_error(mir, infcx, mir_def_id, fr, fr_is_local, fr_region,
372+
outlived_fr, outlived_fr_is_local, outlived_fr_region,
370373
category, span, errors_buffer),
371374
};
372375
}
@@ -377,7 +380,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
377380
infcx: &InferCtxt<'_, '_, 'tcx>,
378381
mir_def_id: DefId,
379382
fr: RegionVid,
383+
fr_region: Option<Region<'tcx>>,
380384
outlived_fr: RegionVid,
385+
outlived_fr_region: Option<Region<'tcx>>,
381386
category: ConstraintCategory,
382387
span: Span,
383388
errors_buffer: &mut Vec<Diagnostic>,
@@ -390,7 +395,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
390395

391396
if fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none() {
392397
return self.report_general_error(mir, infcx, mir_def_id,
393-
fr, true, outlived_fr, false,
398+
fr, true, fr_region,
399+
outlived_fr, false, outlived_fr_region,
394400
category, span, errors_buffer);
395401
}
396402

@@ -430,8 +436,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
430436
mir_def_id: DefId,
431437
fr: RegionVid,
432438
fr_is_local: bool,
439+
fr_region: Option<Region<'tcx>>,
433440
outlived_fr: RegionVid,
434441
outlived_fr_is_local: bool,
442+
outlived_fr_region: Option<Region<'tcx>>,
435443
category: ConstraintCategory,
436444
span: Span,
437445
errors_buffer: &mut Vec<Diagnostic>,
@@ -465,6 +473,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
465473
},
466474
}
467475

476+
if let (Some(f), Some(RegionKind::ReStatic)) = (fr_region, outlived_fr_region) {
477+
if let Some(TyS {
478+
sty: TyKind::Anon(did, _),
479+
..
480+
}) = self.return_type_impl_trait(infcx, f) {
481+
let span = infcx.tcx.def_span(*did);
482+
if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(span) {
483+
diag.span_suggestion(
484+
span,
485+
&format!(
486+
"you can add a constraint to the return type to make it last \
487+
less than `'static` and match {}",
488+
fr_name,
489+
),
490+
format!("{} + {}", snippet, fr_name),
491+
);
492+
}
493+
}
494+
}
495+
468496
diag.buffer(errors_buffer);
469497
}
470498

@@ -490,4 +518,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
490518
let (_, span, _) = self.best_blame_constraint(mir, tcx, fr1, |r| r == fr2);
491519
span
492520
}
521+
522+
fn return_type_impl_trait<'cx>(
523+
&self,
524+
infcx: &'cx InferCtxt<'_, '_, 'tcx>,
525+
outlived_fr_region: Region<'tcx>,
526+
) -> Option<Ty<'cx>> {
527+
infcx.tcx.is_suitable_region(outlived_fr_region)
528+
.map(|r| r.def_id)
529+
.map(|id| infcx.tcx.return_type_impl_trait(id))
530+
.unwrap_or(None)
531+
}
493532
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,20 @@ 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: you can add a constraint to the return type to make it last less than `'static` and match 'a
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+
help: you can add a constraint to the return type to make it last less than `'static` and match 'a
25+
|
26+
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x }
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2028

2129
error: unsatisfied lifetime constraints
2230
--> $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: you can add a constraint to the return type to make it last less than `'static` and match '1
9+
|
10+
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '1 {
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: you can add a constraint to the return type to make it last less than `'static` and match 'a
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)