Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggest to add lifetime constraint at explicit ouput of functions #65730

Merged
merged 3 commits into from
Nov 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2124,6 +2124,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
Expand Down Expand Up @@ -2416,7 +2426,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(),
}))
}
Expand Down Expand Up @@ -2526,7 +2536,7 @@ impl<'a> LoweringContext<'a> {
hir::Lifetime {
hir_id: self.lower_node_id(id),
span,
name: name,
name,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,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)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,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={:?})",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 4 additions & 3 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1552,14 +1552,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) {
Expand All @@ -1580,7 +1580,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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -698,10 +698,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)
Expand Down
29 changes: 29 additions & 0 deletions src/test/ui/async-await/issues/issue-62097.nll.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 19 additions & 0 deletions src/test/ui/async-await/issues/issue-62097.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 16 additions & 0 deletions src/test/ui/async-await/issues/issue-62097.stderr
Original file line number Diff line number Diff line change
@@ -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

4 changes: 0 additions & 4 deletions src/test/ui/async-await/issues/issue-63388-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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