Rollup merge of #65730 - csmoe:return-lifetime, r=nikomatsakis
Suggest to add lifetime constraint at explicit ouput of functions Closes #62097
This commit is contained in:
commit
e4a634189e
12 changed files with 103 additions and 29 deletions
|
|
@ -2170,6 +2170,16 @@ impl<'a> LoweringContext<'a> {
|
|||
impl_trait_return_allow: bool,
|
||||
make_ret_async: Option<NodeId>,
|
||||
) -> P<hir::FnDecl> {
|
||||
debug!("lower_fn_decl(\
|
||||
fn_decl: {:?}, \
|
||||
in_band_ty_params: {:?}, \
|
||||
impl_trait_return_allow: {}, \
|
||||
make_ret_async: {:?})",
|
||||
decl,
|
||||
in_band_ty_params,
|
||||
impl_trait_return_allow,
|
||||
make_ret_async,
|
||||
);
|
||||
let lt_mode = if make_ret_async.is_some() {
|
||||
// In `async fn`, argument-position elided lifetimes
|
||||
// must be transformed into fresh generic parameters so that
|
||||
|
|
@ -2462,7 +2472,7 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
hir::FunctionRetTy::Return(P(hir::Ty {
|
||||
kind: opaque_ty_ref,
|
||||
span,
|
||||
span: opaque_ty_span,
|
||||
hir_id: self.next_id(),
|
||||
}))
|
||||
}
|
||||
|
|
@ -2572,7 +2582,7 @@ impl<'a> LoweringContext<'a> {
|
|||
hir::Lifetime {
|
||||
hir_id: self.lower_node_id(id),
|
||||
span,
|
||||
name: name,
|
||||
name,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
///
|
||||
/// It will later be extended to trait objects.
|
||||
pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
|
||||
let (span, sub, sup) = self.get_regions();
|
||||
let (span, sub, sup) = self.regions();
|
||||
|
||||
// Determine whether the sub and sup consist of both anonymous (elided) regions.
|
||||
let anon_reg_sup = self.tcx().is_suitable_region(sup)?;
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
|
|||
.or_else(|| self.try_report_impl_not_conforming_to_trait())
|
||||
}
|
||||
|
||||
pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
|
||||
pub fn regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
|
||||
match (&self.error, self.regions) {
|
||||
(Some(ConcreteFailure(origin, sub, sup)), None) => (origin.span(), sub, sup),
|
||||
(Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => (origin.span(), sub, sup),
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
/// When given a `ConcreteFailure` for a function with parameters containing a named region and
|
||||
/// an anonymous region, emit an descriptive diagnostic error.
|
||||
pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'a>> {
|
||||
let (span, sub, sup) = self.get_regions();
|
||||
let (span, sub, sup) = self.regions();
|
||||
|
||||
debug!(
|
||||
"try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})",
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
) = error.clone()
|
||||
{
|
||||
let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
|
||||
let return_ty = self.tcx().return_type_impl_trait(anon_reg_sup.def_id);
|
||||
if sub_r == &RegionKind::ReStatic &&
|
||||
self.tcx().return_type_impl_trait(anon_reg_sup.def_id).is_some()
|
||||
return_ty.is_some()
|
||||
{
|
||||
let sp = var_origin.span();
|
||||
let return_sp = sub_origin.span();
|
||||
|
|
@ -52,17 +53,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
}) => name.to_string(),
|
||||
_ => "'_".to_owned(),
|
||||
};
|
||||
if let Ok(snippet) = self.tcx().sess.source_map().span_to_snippet(return_sp) {
|
||||
err.span_suggestion(
|
||||
return_sp,
|
||||
&format!(
|
||||
"you can add a constraint to the return type to make it last \
|
||||
let fn_return_span = return_ty.unwrap().1;
|
||||
if let Ok(snippet) =
|
||||
self.tcx().sess.source_map().span_to_snippet(fn_return_span) {
|
||||
// only apply this suggestion onto functions with
|
||||
// explicit non-desugar'able return.
|
||||
if fn_return_span.desugaring_kind().is_none() {
|
||||
err.span_suggestion(
|
||||
fn_return_span,
|
||||
&format!(
|
||||
"you can add a constraint to the return type to make it last \
|
||||
less than `'static` and match {}",
|
||||
lifetime,
|
||||
),
|
||||
format!("{} + {}", snippet, lifetime_name),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
lifetime,
|
||||
),
|
||||
format!("{} + {}", snippet, lifetime_name),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
return Some(ErrorReported);
|
||||
|
|
|
|||
|
|
@ -1529,14 +1529,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
return Some(FreeRegionInfo {
|
||||
def_id: suitable_region_binding_scope,
|
||||
boundregion: bound_region,
|
||||
is_impl_item: is_impl_item,
|
||||
is_impl_item,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn return_type_impl_trait(
|
||||
&self,
|
||||
scope_def_id: DefId,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
) -> Option<(Ty<'tcx>, Span)> {
|
||||
// HACK: `type_of_def_id()` will fail on these (#55796), so return `None`.
|
||||
let hir_id = self.hir().as_local_hir_id(scope_def_id).unwrap();
|
||||
match self.hir().get(hir_id) {
|
||||
|
|
@ -1557,7 +1557,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let sig = ret_ty.fn_sig(*self);
|
||||
let output = self.erase_late_bound_regions(&sig.output());
|
||||
if output.is_impl_trait() {
|
||||
Some(output)
|
||||
let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
|
||||
Some((output, fn_decl.output.span()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -715,10 +715,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
if let (Some(f), Some(ty::RegionKind::ReStatic)) =
|
||||
(self.to_error_region(fr), self.to_error_region(outlived_fr))
|
||||
{
|
||||
if let Some(ty::TyS {
|
||||
if let Some((ty::TyS {
|
||||
kind: ty::Opaque(did, substs),
|
||||
..
|
||||
}) = infcx
|
||||
}, _)) = infcx
|
||||
.tcx
|
||||
.is_suitable_region(f)
|
||||
.map(|r| r.def_id)
|
||||
|
|
|
|||
29
src/test/ui/async-await/issues/issue-62097.nll.stderr
Normal file
29
src/test/ui/async-await/issues/issue-62097.nll.stderr
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
error[E0373]: closure may outlive the current function, but it borrows `self`, which is owned by the current function
|
||||
--> $DIR/issue-62097.rs:13:13
|
||||
|
|
||||
LL | foo(|| self.bar()).await;
|
||||
| ^^ ---- `self` is borrowed here
|
||||
| |
|
||||
| may outlive borrowed value `self`
|
||||
|
|
||||
note: function requires argument type to outlive `'static`
|
||||
--> $DIR/issue-62097.rs:13:9
|
||||
|
|
||||
LL | foo(|| self.bar()).await;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
LL | foo(move || self.bar()).await;
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0521]: borrowed data escapes outside of function
|
||||
--> $DIR/issue-62097.rs:13:9
|
||||
|
|
||||
LL | pub async fn run_dummy_fn(&self) {
|
||||
| ----- `self` is a reference that is only valid in the function body
|
||||
LL | foo(|| self.bar()).await;
|
||||
| ^^^^^^^^^^^^^^^^^^ `self` escapes the function body here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0373`.
|
||||
19
src/test/ui/async-await/issues/issue-62097.rs
Normal file
19
src/test/ui/async-await/issues/issue-62097.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// edition:2018
|
||||
async fn foo<F>(fun: F)
|
||||
where
|
||||
F: FnOnce() + 'static
|
||||
{
|
||||
fun()
|
||||
}
|
||||
|
||||
struct Struct;
|
||||
|
||||
impl Struct {
|
||||
pub async fn run_dummy_fn(&self) { //~ ERROR cannot infer
|
||||
foo(|| self.bar()).await;
|
||||
}
|
||||
|
||||
pub fn bar(&self) {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
16
src/test/ui/async-await/issues/issue-62097.stderr
Normal file
16
src/test/ui/async-await/issues/issue-62097.stderr
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
error: cannot infer an appropriate lifetime
|
||||
--> $DIR/issue-62097.rs:12:31
|
||||
|
|
||||
LL | pub async fn run_dummy_fn(&self) {
|
||||
| ^^^^^ ...but this borrow...
|
||||
LL | foo(|| self.bar()).await;
|
||||
| --- this return type evaluates to the `'static` lifetime...
|
||||
|
|
||||
note: ...can't outlive the lifetime `'_` as defined on the method body at 12:31
|
||||
--> $DIR/issue-62097.rs:12:31
|
||||
|
|
||||
LL | pub async fn run_dummy_fn(&self) {
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -20,10 +20,6 @@ note: ...can't outlive the lifetime `'_` as defined on the method body at 11:14
|
|||
|
|
||||
LL | foo: &dyn Foo, bar: &'a dyn Foo
|
||||
| ^
|
||||
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'_` as defined on the method body at 11:14
|
||||
|
|
||||
LL | foo + '_
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,6 @@ note: ...can't outlive the lifetime `'_` as defined on the method body at 8:26
|
|||
|
|
||||
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
|
||||
| ^
|
||||
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'_` as defined on the method body at 8:26
|
||||
|
|
||||
LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue