Added help message for impl trait static constraint.

This commit is contained in:
David Wood 2018-09-02 11:10:51 +02:00
parent 78b21643a8
commit 6bf131f3f4
No known key found for this signature in database
GPG key ID: 01760B4F9F53F154
5 changed files with 73 additions and 15 deletions

View file

@ -29,7 +29,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
) => {
let anon_reg_sup = self.tcx.is_suitable_region(sup_r)?;
if sub_r == &RegionKind::ReStatic &&
self.tcx.is_return_type_impl_trait(anon_reg_sup.def_id)
self.tcx.return_type_impl_trait(anon_reg_sup.def_id).is_some()
{
let sp = var_origin.span();
let return_sp = sub_origin.span();

View file

@ -1587,20 +1587,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
});
}
pub fn is_return_type_impl_trait(
pub fn return_type_impl_trait(
&self,
scope_def_id: DefId,
) -> bool {
) -> Option<Ty> {
let ret_ty = self.type_of(scope_def_id);
match ret_ty.sty {
ty::FnDef(_, _) => {
let sig = ret_ty.fn_sig(*self);
let output = self.erase_late_bound_regions(&sig.output());
return output.is_impl_trait();
if output.is_impl_trait() {
Some(output)
} else {
None
}
}
_ => {}
_ => None
}
false
}
// Here we check if the bound region is in Impl Item.

View file

@ -15,7 +15,7 @@ use rustc::hir::def_id::DefId;
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc::infer::InferCtxt;
use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind};
use rustc::ty::{TyCtxt, RegionVid};
use rustc::ty::{TyCtxt, Ty, TyS, TyKind, Region, RegionKind, RegionVid};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_errors::Diagnostic;
use std::collections::VecDeque;
@ -344,7 +344,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
);
// Check if we can use one of the "nice region errors".
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
let fr_region = self.to_error_region(fr);
let outlived_fr_region = self.to_error_region(outlived_fr);
if let (Some(f), Some(o)) = (fr_region, outlived_fr_region) {
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
let nice = NiceRegionError::new_from_span(infcx.tcx, span, o, f, Some(tables));
if let Some(_error_reported) = nice.try_report_from_nll() {
@ -356,17 +358,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.universal_regions.is_local_free_region(fr),
self.universal_regions.is_local_free_region(outlived_fr),
);
debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
fr_is_local, outlived_fr_is_local, category);
debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} fr_region={:?} \
outlived_fr_region={:?} category={:?}",
fr_is_local, outlived_fr_is_local, fr_region, outlived_fr_region, category);
match (category, fr_is_local, outlived_fr_is_local) {
(ConstraintCategory::Assignment, true, false) |
(ConstraintCategory::CallArgument, true, false) =>
self.report_escaping_data_error(mir, infcx, mir_def_id, fr, outlived_fr,
category, span, errors_buffer),
self.report_escaping_data_error(mir, infcx, mir_def_id, fr, fr_region, outlived_fr,
outlived_fr_region, category, span, errors_buffer),
_ =>
self.report_general_error(mir, infcx, mir_def_id, fr, fr_is_local,
outlived_fr, outlived_fr_is_local,
self.report_general_error(mir, infcx, mir_def_id, fr, fr_is_local, fr_region,
outlived_fr, outlived_fr_is_local, outlived_fr_region,
category, span, errors_buffer),
};
}
@ -377,7 +380,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
infcx: &InferCtxt<'_, '_, 'tcx>,
mir_def_id: DefId,
fr: RegionVid,
fr_region: Option<Region<'tcx>>,
outlived_fr: RegionVid,
outlived_fr_region: Option<Region<'tcx>>,
category: ConstraintCategory,
span: Span,
errors_buffer: &mut Vec<Diagnostic>,
@ -390,7 +395,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none() {
return self.report_general_error(mir, infcx, mir_def_id,
fr, true, outlived_fr, false,
fr, true, fr_region,
outlived_fr, false, outlived_fr_region,
category, span, errors_buffer);
}
@ -430,8 +436,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
mir_def_id: DefId,
fr: RegionVid,
fr_is_local: bool,
fr_region: Option<Region<'tcx>>,
outlived_fr: RegionVid,
outlived_fr_is_local: bool,
outlived_fr_region: Option<Region<'tcx>>,
category: ConstraintCategory,
span: Span,
errors_buffer: &mut Vec<Diagnostic>,
@ -465,6 +473,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
},
}
if let (Some(f), Some(RegionKind::ReStatic)) = (fr_region, outlived_fr_region) {
if let Some(TyS {
sty: TyKind::Anon(did, _),
..
}) = self.return_type_impl_trait(infcx, f) {
let span = infcx.tcx.def_span(*did);
if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(span) {
diag.span_suggestion(
span,
&format!(
"you can add a constraint to the return type to make it last \
less than `'static` and match {}",
fr_name,
),
format!("{} + {}", snippet, fr_name),
);
}
}
}
diag.buffer(errors_buffer);
}
@ -490,4 +518,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let (_, span, _) = self.best_blame_constraint(mir, tcx, fr1, |r| r == fr2);
span
}
fn return_type_impl_trait<'cx>(
&self,
infcx: &'cx InferCtxt<'_, '_, 'tcx>,
outlived_fr_region: Region<'tcx>,
) -> Option<Ty<'cx>> {
infcx.tcx.is_suitable_region(outlived_fr_region)
.map(|r| r.def_id)
.map(|id| infcx.tcx.return_type_impl_trait(id))
.unwrap_or(None)
}
}

View file

@ -11,12 +11,20 @@ error: unsatisfied lifetime constraints
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
help: you can add a constraint to the return type to make it last less than `'static` and match 'a
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^^^^^^^^^^^
error: unsatisfied lifetime constraints
--> $DIR/must_outlive_least_region_or_bound.rs:22:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
help: you can add a constraint to the return type to make it last less than `'static` and match 'a
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: unsatisfied lifetime constraints
--> $DIR/must_outlive_least_region_or_bound.rs:29:5

View file

@ -5,6 +5,10 @@ LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
| - let's call the lifetime of this reference `'1`
LL | self.x.iter().map(|a| a.0)
| ^^^^^^ cast requires that `'1` must outlive `'static`
help: you can add a constraint to the return type to make it last less than `'static` and match '1
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '1 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: unsatisfied lifetime constraints
--> $DIR/static-return-lifetime-infered.rs:21:9
@ -13,6 +17,10 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| -- lifetime `'a` defined here
LL | self.x.iter().map(|a| a.0)
| ^^^^^^ cast requires that `'a` must outlive `'static`
help: you can add a constraint to the return type to make it last less than `'static` and match 'a
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors