Skip to content

Commit b4cf523

Browse files
authored
Rollup merge of #93582 - WaffleLapkin:rpitirpit, r=compiler-errors
Allow `impl Fn() -> impl Trait` in return position _This was originally proposed as part of #93082 which was [closed](#93082 (comment)) due to allowing `impl Fn() -> impl Trait` in argument position._ This allows writing the following function signatures: ```rust fn f0() -> impl Fn() -> impl Trait; fn f3() -> &'static dyn Fn() -> impl Trait; ``` These signatures were already allowed for common traits and associated types, there is no reason why `Fn*` traits should be special in this regard. `impl Trait` in both `f0` and `f3` means "new existential type", just like with `-> impl Iterator<Item = impl Trait>` and such. Arrow in `impl Fn() ->` is right-associative and binds from right to left, it's tested by [this test](https://github.com/WaffleLapkin/rust/blob/a819fecb8dea438fc70488ddec30a61e52942672/src/test/ui/impl-trait/impl_fn_associativity.rs). There even is a test that `f0` compiles: https://github.com/rust-lang/rust/blob/2f004d2d401682e553af3984ebd9a3976885e752/src/test/ui/impl-trait/nested_impl_trait.rs#L25-L28 But it was changed in [PR 48084 (lines)](https://github.com/rust-lang/rust/pull/48084/files#diff-ccecca938872d65ffe8cd1c3ef1956e309fac83bcda547d8b16b89257e53a437R37) to test the opposite, probably unintentionally given [PR 48084 (lines)](https://github.com/rust-lang/rust/pull/48084/files#diff-5a02f1ed43debed1fd24f7aad72490064f795b9420f15d847bac822aa4621a1cR476-R477). r? `@nikomatsakis` ---- This limitation is especially annoying with async code, since it forces one to write this: ```rust trait AsyncFn3<A, B, C>: Fn(A, B, C) -> <Self as AsyncFn3<A, B, C>>::Future { type Future: Future<Output = Self::Out>; type Out; } impl<A, B, C, Fut, F> AsyncFn3<A, B, C> for F where F: Fn(A, B, C) -> Fut, Fut: Future, { type Future = Fut; type Out = Fut::Output; } fn async_closure() -> impl AsyncFn3<i32, i32, i32, Out = u32> { |a, b, c| async move { (a + b + c) as u32 } } ``` Instead of: ```rust fn async_closure() -> impl Fn(i32, i32, i32) -> impl Future<Output = u32> { |a, b, c| async move { (a + b + c) as u32 } } ```
2 parents 4827cee + e93982a commit b4cf523

18 files changed

+295
-76
lines changed

compiler/rustc_ast_lowering/src/path.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
191191
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
192192
}
193193
GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
194-
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
194+
ParenthesizedGenericArgs::Ok => {
195+
self.lower_parenthesized_parameter_data(data, itctx)
196+
}
195197
ParenthesizedGenericArgs::Err => {
196198
// Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
197199
let sub = if !data.inputs.is_empty() {
@@ -344,6 +346,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
344346
fn lower_parenthesized_parameter_data(
345347
&mut self,
346348
data: &ParenthesizedArgs,
349+
itctx: &ImplTraitContext,
347350
) -> (GenericArgsCtor<'hir>, bool) {
348351
// Switch to `PassThrough` mode for anonymous lifetimes; this
349352
// means that we permit things like `&Ref<T>`, where `Ref` has
@@ -355,6 +358,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
355358
self.lower_ty_direct(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
356359
}));
357360
let output_ty = match output {
361+
// Only allow `impl Trait` in return position. i.e.:
362+
// ```rust
363+
// fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug
364+
// // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
365+
// ```
366+
FnRetTy::Ty(ty)
367+
if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. })
368+
&& self.tcx.features().impl_trait_in_fn_trait_return =>
369+
{
370+
self.lower_ty(&ty, itctx)
371+
}
358372
FnRetTy::Ty(ty) => {
359373
self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
360374
}

compiler/rustc_feature/src/active.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,8 @@ declare_features! (
412412
(active, half_open_range_patterns_in_slices, "CURRENT_RUSTC_VERSION", Some(67264), None),
413413
/// Allows `if let` guard in match arms.
414414
(active, if_let_guard, "1.47.0", Some(51114), None),
415+
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
416+
(active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None),
415417
/// Allows using imported `main` function
416418
(active, imported_main, "1.53.0", Some(28937), None),
417419
/// Allows associated types in inherent impls.

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,7 @@ symbols! {
813813
impl_lint_pass,
814814
impl_macros,
815815
impl_trait_in_bindings,
816+
impl_trait_in_fn_trait_return,
816817
implied_by,
817818
import,
818819
import_name_type,
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fn f() -> impl Fn() -> impl Sized { || () }
2+
//~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
3+
fn g() -> &'static dyn Fn() -> impl Sized { &|| () }
4+
//~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
5+
6+
fn main() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
2+
--> $DIR/feature-gate-impl_trait_in_fn_trait_return.rs:1:24
3+
|
4+
LL | fn f() -> impl Fn() -> impl Sized { || () }
5+
| ^^^^^^^^^^
6+
7+
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
8+
--> $DIR/feature-gate-impl_trait_in_fn_trait_return.rs:3:32
9+
|
10+
LL | fn g() -> &'static dyn Fn() -> impl Sized { &|| () }
11+
| ^^^^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0562`.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(impl_trait_in_fn_trait_return)]
2+
use std::fmt::Debug;
3+
4+
fn a() -> impl Fn(&u8) -> impl Debug {
5+
|x| x //~ ERROR hidden type for `impl Debug` captures lifetime that does not appear in bounds
6+
}
7+
8+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0700]: hidden type for `impl Debug` captures lifetime that does not appear in bounds
2+
--> $DIR/impl-fn-hrtb-bounds-2.rs:5:9
3+
|
4+
LL | |x| x
5+
| --- ^
6+
| |
7+
| hidden type `&u8` captures the anonymous lifetime #1 defined here
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0700`.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(impl_trait_in_fn_trait_return)]
2+
use std::fmt::Debug;
3+
4+
fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
5+
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
6+
|x| x
7+
}
8+
9+
fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
10+
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
11+
|x| x
12+
}
13+
14+
fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
15+
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
16+
|x| x
17+
}
18+
19+
fn d() -> impl Fn() -> (impl Debug + '_) {
20+
//~^ ERROR missing lifetime specifier
21+
|| ()
22+
}
23+
24+
fn main() {}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
error[E0106]: missing lifetime specifier
2+
--> $DIR/impl-fn-hrtb-bounds.rs:19:38
3+
|
4+
LL | fn d() -> impl Fn() -> (impl Debug + '_) {
5+
| ^^ expected named lifetime parameter
6+
|
7+
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
8+
help: consider using the `'static` lifetime
9+
|
10+
LL | fn d() -> impl Fn() -> (impl Debug + 'static) {
11+
| ~~~~~~~
12+
13+
error: higher kinded lifetime bounds on nested opaque types are not supported yet
14+
--> $DIR/impl-fn-hrtb-bounds.rs:4:41
15+
|
16+
LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
17+
| ^^
18+
|
19+
note: lifetime declared here
20+
--> $DIR/impl-fn-hrtb-bounds.rs:4:19
21+
|
22+
LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
23+
| ^
24+
25+
error: higher kinded lifetime bounds on nested opaque types are not supported yet
26+
--> $DIR/impl-fn-hrtb-bounds.rs:9:52
27+
|
28+
LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
29+
| ^^
30+
|
31+
note: lifetime declared here
32+
--> $DIR/impl-fn-hrtb-bounds.rs:9:20
33+
|
34+
LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
35+
| ^^
36+
37+
error: higher kinded lifetime bounds on nested opaque types are not supported yet
38+
--> $DIR/impl-fn-hrtb-bounds.rs:14:52
39+
|
40+
LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
41+
| ^^
42+
|
43+
note: lifetime declared here
44+
--> $DIR/impl-fn-hrtb-bounds.rs:14:20
45+
|
46+
LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
47+
| ^^
48+
49+
error: aborting due to 4 previous errors
50+
51+
For more information about this error, try `rustc --explain E0106`.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(impl_trait_in_fn_trait_return)]
2+
use std::fmt::Debug;
3+
4+
fn a() -> impl Fn(&u8) -> impl Debug + '_ {
5+
//~^ ERROR ambiguous `+` in a type
6+
//~^^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
7+
|x| x
8+
}
9+
10+
fn b() -> impl Fn() -> impl Debug + Send {
11+
//~^ ERROR ambiguous `+` in a type
12+
|| ()
13+
}
14+
15+
fn main() {}

0 commit comments

Comments
 (0)