&self lifetime elision with two parameters does not work with async fn #63388
Copy link
Copy link
Closed
Labels
A-async-awaitArea: Async & AwaitArea: Async & AwaitA-inferenceArea: Type inferenceArea: Type inferenceA-lifetimesArea: Lifetimes / regionsArea: Lifetimes / regionsA-type-systemArea: Type systemArea: Type systemAsyncAwait-PolishAsync-await issues that are part of the "polish" areaAsync-await issues that are part of the "polish" areaC-bugCategory: This is a bug.Category: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.This issue requires a nightly compiler in some way. When possible, use a F-* label instead.
Description
Originally reported in #63383 (comment).
#![feature(async_await)]
#![feature(nll)]
// Without it you also get //~^ ERROR cannot infer an appropriate lifetime
struct A;
impl A {
async fn foo(&self, f: &u32) -> &A {
self
}
}should compile (it does if you remove async or write async fn foo<'a, 'b>(&'a self, f: &'b u32) -> &'a A) but does not (playground):
error[E0106]: missing lifetime specifier
--> src/lib.rs:7:37
|
7 | async fn foo(&self, f: &u32) -> &A {
| ^
|
= note: return-position elided lifetimes require exactly one input-position elided lifetime, found multiple.This seems like a rather serious usability bug as compared to what you expect from normal Rust.
cc #63209
cc @nikomatsakis @cramertj
Metadata
Metadata
Assignees
Labels
A-async-awaitArea: Async & AwaitArea: Async & AwaitA-inferenceArea: Type inferenceArea: Type inferenceA-lifetimesArea: Lifetimes / regionsArea: Lifetimes / regionsA-type-systemArea: Type systemArea: Type systemAsyncAwait-PolishAsync-await issues that are part of the "polish" areaAsync-await issues that are part of the "polish" areaC-bugCategory: This is a bug.Category: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.This issue requires a nightly compiler in some way. When possible, use a F-* label instead.
Activity
[-]`&self` lifetime elision with two arguments does not work with `async fn`[/-][+]`&self` lifetime elision with two parameters does not work with `async fn`[/+]cramertj commentedon Aug 8, 2019
The code that calculates
LtReplacementin lowering is wrong-- it should give preference to the lifetime coming fromselfover other lifetimes from the function signature.nikomatsakis commentedon Aug 12, 2019
OK, so, a few thoughts:
I agree this is a serious usability bug. It's not a forward a compatibility hazard, though.
Regarding the code itself, it's a shame that we have to duplicate the elision code -- there are currently two bits of code doing the same check. The one in lowering is the one giving us the error here. The error is also phrased slightly differently than the one from lifetime resolution.
We could probably get this to work correctly for
&selfand&mut self. The logic for cases likeself: &Self, as we've seen, is somewhat more complex, and before trying to handle that, I'd want to see if we can't reduce the duplication/I feel like ultimately I'd hate to hold off on shipping async-await owing to this bug, but it'd be good to fix it.
nikomatsakis commentedon Aug 12, 2019
@cramertj so I guess the buggy code is this:
rust/src/librustc/hir/lowering.rs
Lines 2159 to 2163 in 60960a2
presumably the way to make it work for
&selfand&mut selfwould be to check theimplicit_selffield of thedeclparameter. If it isImmReforMutRef, then I would guess we should just useLtReplacement::Some(self.lifetimes_to_define[lifetime_count_before_args])always.nikomatsakis commentedon Aug 12, 2019
Er, my mistake, you can't match on the
implicit_selffield, but rather promote this computation earlier:rust/src/librustc/hir/lowering.rs
Lines 2190 to 2214 in 60960a2
nikomatsakis commentedon Aug 12, 2019
(TBH I'm not 100% sure this code is right, so I'm doing a quick test locally to see if I'm remembering things correctly.)
nikomatsakis commentedon Aug 12, 2019
Actually, the behavior of the current code is (I think) worse than the issue suggests. If I understand what it's doing -- it is looking for exactly one lifetime parameter that was not explicitly declared, and using that as the elided lifetime.
so for example this code compiles which should not (playground):
as does this (playground):
nikomatsakis commentedon Aug 12, 2019
I have a nice fix now.
Rollup merge of rust-lang#63499 - nikomatsakis:issuee-63388-async-fn-…
Rollup merge of rust-lang#63499 - nikomatsakis:issuee-63388-async-fn-…
Rollup merge of rust-lang#63499 - nikomatsakis:issuee-63388-async-fn-…
Rollup merge of rust-lang#63209 - Centril:stabilize-async-await, r=cr…