Added help message for impl trait static constraint.
This commit is contained in:
parent
78b21643a8
commit
6bf131f3f4
5 changed files with 73 additions and 15 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue