Skip to content

Commit e467840

Browse files
committed
NiceRegionError: Use written return type for async fn
1 parent cca0aa9 commit e467840

13 files changed

+181
-165
lines changed

compiler/rustc_hir/src/hir.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -2731,6 +2731,10 @@ pub struct FnHeader {
27312731
}
27322732

27332733
impl FnHeader {
2734+
pub fn is_async(&self) -> bool {
2735+
matches!(&self.asyncness, IsAsync::Async)
2736+
}
2737+
27342738
pub fn is_const(&self) -> bool {
27352739
matches!(&self.constness, Constness::Const)
27362740
}
@@ -3175,7 +3179,7 @@ impl<'hir> Node<'hir> {
31753179
}
31763180
}
31773181

3178-
pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
3182+
pub fn fn_decl(&self) -> Option<&'hir FnDecl<'hir>> {
31793183
match self {
31803184
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
31813185
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
@@ -3187,6 +3191,15 @@ impl<'hir> Node<'hir> {
31873191
}
31883192
}
31893193

3194+
pub fn fn_sig(&self) -> Option<&'hir FnSig<'hir>> {
3195+
match self {
3196+
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
3197+
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
3198+
| Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig),
3199+
_ => None,
3200+
}
3201+
}
3202+
31903203
pub fn body_id(&self) -> Option<BodyId> {
31913204
match self {
31923205
Node::TraitItem(TraitItem {

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ use rustc_hir::def_id::DefId;
6565
use rustc_hir::lang_items::LangItem;
6666
use rustc_hir::{Item, ItemKind, Node};
6767
use rustc_middle::dep_graph::DepContext;
68-
use rustc_middle::ty::error::TypeError;
6968
use rustc_middle::ty::{
7069
self,
70+
error::TypeError,
7171
subst::{GenericArgKind, Subst, SubstsRef},
7272
Binder, Region, Ty, TyCtxt, TypeFoldable,
7373
};

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
171171

172172
self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
173173

174+
// TODO: This is only helpful if the lifetime more visible in the impl Future type than in the signature.
174175
if let Some(t) = future_return_type {
175176
let snip = self
176177
.tcx()

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs

+6-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use rustc_hir as hir;
22
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
3-
use rustc_hir::Node;
43
use rustc_middle::hir::map::Map;
54
use rustc_middle::middle::resolve_lifetime as rl;
65
use rustc_middle::ty::{self, Region, TyCtxt};
@@ -24,25 +23,19 @@ pub(crate) fn find_anon_type<'tcx>(
2423
tcx: TyCtxt<'tcx>,
2524
region: Region<'tcx>,
2625
br: &ty::BoundRegionKind,
27-
) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnDecl<'tcx>)> {
26+
) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> {
2827
if let Some(anon_reg) = tcx.is_suitable_region(region) {
2928
let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
30-
let fndecl = match tcx.hir().get(hir_id) {
31-
Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
32-
| Node::TraitItem(&hir::TraitItem {
33-
kind: hir::TraitItemKind::Fn(ref m, ..), ..
34-
})
35-
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref m, ..), .. }) => {
36-
&m.decl
37-
}
38-
_ => return None,
29+
let Some(fn_sig) = tcx.hir().get(hir_id).fn_sig() else {
30+
return None
3931
};
4032

41-
fndecl
33+
fn_sig
34+
.decl
4235
.inputs
4336
.iter()
4437
.find_map(|arg| find_component_for_bound_region(tcx, arg, br))
45-
.map(|ty| (ty, &**fndecl))
38+
.map(|ty| (ty, fn_sig))
4639
} else {
4740
None
4841
}

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs

+26-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
55
use rustc_hir as hir;
66
use rustc_hir::def_id::LocalDefId;
7-
use rustc_middle::ty::{self, DefIdTree, Region, Ty};
7+
use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeFoldable};
88
use rustc_span::Span;
99

1010
/// Information about the anonymous region we are searching for.
@@ -148,26 +148,41 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
148148
}
149149

150150
// Here, we check for the case where the anonymous region
151-
// is in the return type.
151+
// is in the return type as written by the user.
152152
// FIXME(#42703) - Need to handle certain cases here.
153153
pub(super) fn is_return_type_anon(
154154
&self,
155155
scope_def_id: LocalDefId,
156156
br: ty::BoundRegionKind,
157-
decl: &hir::FnDecl<'_>,
157+
hir_sig: &hir::FnSig<'_>,
158158
) -> Option<Span> {
159-
let ret_ty = self.tcx().type_of(scope_def_id);
160-
if let ty::FnDef(_, _) = ret_ty.kind() {
161-
let sig = ret_ty.fn_sig(self.tcx());
162-
let late_bound_regions =
163-
self.tcx().collect_referenced_late_bound_regions(&sig.output());
164-
if late_bound_regions.iter().any(|r| *r == br) {
165-
return Some(decl.output.span());
166-
}
159+
let fn_ty = self.tcx().type_of(scope_def_id);
160+
if let ty::FnDef(_, _) = fn_ty.kind() {
161+
let ret_ty = fn_ty.fn_sig(self.tcx()).output();
162+
let span = hir_sig.decl.output.span();
163+
let future_output = if hir_sig.header.is_async() {
164+
ret_ty.map_bound(|ty| self.infcx.get_impl_future_output_ty(ty)).transpose()
165+
} else {
166+
None
167+
};
168+
return match future_output {
169+
Some(output) if self.includes_region(output, br) => Some(span),
170+
None if self.includes_region(ret_ty, br) => Some(span),
171+
_ => None,
172+
};
167173
}
168174
None
169175
}
170176

177+
fn includes_region(
178+
&self,
179+
ty: Binder<'tcx, impl TypeFoldable<'tcx>>,
180+
region: ty::BoundRegionKind,
181+
) -> bool {
182+
let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty);
183+
late_bound_regions.iter().any(|r| *r == region)
184+
}
185+
171186
// Here we check for the case where anonymous region
172187
// corresponds to self and if yes, we display E0312.
173188
// FIXME(#42700) - Need to format self properly to

src/test/ui/async-await/issue-76547.stderr

+4-10
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,17 @@ error[E0623]: lifetime mismatch
22
--> $DIR/issue-76547.rs:20:13
33
|
44
LL | async fn fut(bufs: &mut [&mut [u8]]) {
5-
| --------- -
6-
| | |
7-
| | this `async fn` implicitly returns an `impl Future<Output = ()>`
8-
| this parameter and the returned future are declared with different lifetimes...
5+
| ---------------- these two types are declared with different lifetimes...
96
LL | ListFut(bufs).await
10-
| ^^^^ ...but data from `bufs` is held across an await point here
7+
| ^^^^ ...but data from `bufs` flows into `bufs` here
118

129
error[E0623]: lifetime mismatch
1310
--> $DIR/issue-76547.rs:34:14
1411
|
1512
LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
16-
| --------- ---
17-
| | |
18-
| | this `async fn` implicitly returns an `impl Future<Output = i32>`
19-
| this parameter and the returned future are declared with different lifetimes...
13+
| ---------------- these two types are declared with different lifetimes...
2014
LL | ListFut2(bufs).await
21-
| ^^^^ ...but data from `bufs` is held across an await point here
15+
| ^^^^ ...but data from `bufs` flows into `bufs` here
2216

2317
error: aborting due to 2 previous errors
2418

src/test/ui/async-await/issues/issue-63388-1.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0623]: lifetime mismatch
22
--> $DIR/issue-63388-1.rs:14:9
33
|
44
LL | &'a self, foo: &dyn Foo
5-
| -------- this parameter and the returned future are declared with different lifetimes...
5+
| -------- this parameter and the returned future are declared with different lifetimes...
66
LL | ) -> &dyn Foo
77
| --------
88
| |

src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,28 @@ error[E0623]: lifetime mismatch
22
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
33
|
44
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
5-
| ---- ---- ^ ...but data from `f` is held across an await point here
6-
| | |
7-
| | this `async fn` implicitly returns an `impl Future<Output = &Foo>`
8-
| this parameter and the returned future are declared with different lifetimes...
5+
| ---- ---- ^ ...but data from `f` is held across an await point here
6+
| | |
7+
| | this `async fn` implicitly returns an `impl Future<Output = &Foo>`
8+
| this parameter and the returned future are declared with different lifetimes...
99

1010
error[E0623]: lifetime mismatch
1111
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:82
1212
|
1313
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
14-
| ----- ----------------- ^ ...but data from `f` is held across an await point here
15-
| | |
16-
| | this `async fn` implicitly returns an `impl Future<Output = (Pin<&Foo>, &Foo)>`
17-
| this parameter and the returned future are declared with different lifetimes...
14+
| ---- ----------------- ^ ...but data from `f` is held across an await point here
15+
| | |
16+
| | this `async fn` implicitly returns an `impl Future<Output = (Pin<&Foo>, &Foo)>`
17+
| this parameter and the returned future are declared with different lifetimes...
1818

1919
error[E0623]: lifetime mismatch
2020
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
2121
|
2222
LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
23-
| ----- --- ^^^ ...but data from `arg` is held across an await point here
24-
| | |
25-
| | this `async fn` implicitly returns an `impl Future<Output = &()>`
26-
| this parameter and the returned future are declared with different lifetimes...
23+
| ------ --- ^^^ ...but data from `arg` is held across an await point here
24+
| | |
25+
| | this `async fn` implicitly returns an `impl Future<Output = &()>`
26+
| this parameter and the returned future are declared with different lifetimes...
2727

2828
error: aborting due to 3 previous errors
2929

src/test/ui/self/elision/lt-ref-self-async.stderr

+24-24
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,65 @@ error[E0623]: lifetime mismatch
22
--> $DIR/lt-ref-self-async.rs:13:9
33
|
44
LL | async fn ref_self(&self, f: &u32) -> &u32 {
5-
| ----- ----
6-
| | |
7-
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
8-
| this parameter and the returned future are declared with different lifetimes...
5+
| ---- ----
6+
| | |
7+
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
8+
| this parameter and the returned future are declared with different lifetimes...
99
LL | f
1010
| ^ ...but data from `f` is held across an await point here
1111

1212
error[E0623]: lifetime mismatch
1313
--> $DIR/lt-ref-self-async.rs:19:9
1414
|
1515
LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
16-
| ----- ----
17-
| | |
18-
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
19-
| this parameter and the returned future are declared with different lifetimes...
16+
| ---- ----
17+
| | |
18+
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
19+
| this parameter and the returned future are declared with different lifetimes...
2020
LL | f
2121
| ^ ...but data from `f` is held across an await point here
2222

2323
error[E0623]: lifetime mismatch
2424
--> $DIR/lt-ref-self-async.rs:23:9
2525
|
2626
LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
27-
| ----- ----
28-
| | |
29-
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
30-
| this parameter and the returned future are declared with different lifetimes...
27+
| ---- ----
28+
| | |
29+
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
30+
| this parameter and the returned future are declared with different lifetimes...
3131
LL | f
3232
| ^ ...but data from `f` is held across an await point here
3333

3434
error[E0623]: lifetime mismatch
3535
--> $DIR/lt-ref-self-async.rs:27:9
3636
|
3737
LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
38-
| ----- ----
39-
| | |
40-
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
41-
| this parameter and the returned future are declared with different lifetimes...
38+
| ---- ----
39+
| | |
40+
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
41+
| this parameter and the returned future are declared with different lifetimes...
4242
LL | f
4343
| ^ ...but data from `f` is held across an await point here
4444

4545
error[E0623]: lifetime mismatch
4646
--> $DIR/lt-ref-self-async.rs:31:9
4747
|
4848
LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
49-
| ----- ----
50-
| | |
51-
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
52-
| this parameter and the returned future are declared with different lifetimes...
49+
| ---- ----
50+
| | |
51+
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
52+
| this parameter and the returned future are declared with different lifetimes...
5353
LL | f
5454
| ^ ...but data from `f` is held across an await point here
5555

5656
error[E0623]: lifetime mismatch
5757
--> $DIR/lt-ref-self-async.rs:35:9
5858
|
5959
LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
60-
| ----- ----
61-
| | |
62-
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
63-
| this parameter and the returned future are declared with different lifetimes...
60+
| ---- ----
61+
| | |
62+
| | this `async fn` implicitly returns an `impl Future<Output = &u32>`
63+
| this parameter and the returned future are declared with different lifetimes...
6464
LL | f
6565
| ^ ...but data from `f` is held across an await point here
6666

0 commit comments

Comments
 (0)