Skip to content

Commit 8b494f4

Browse files
committed
Allow impl Fn() -> impl Trait in return 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.
1 parent 1481fd9 commit 8b494f4

File tree

6 files changed

+73
-67
lines changed

6 files changed

+73
-67
lines changed

compiler/rustc_ast_lowering/src/path.rs

Lines changed: 12 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,14 @@ 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) if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. }) => {
367+
self.lower_ty(&ty, itctx)
368+
}
358369
FnRetTy::Ty(ty) => {
359370
self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
360371
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// run-pass
2+
use std::fmt::Debug;
3+
4+
fn f_debug() -> impl Fn() -> impl Debug {
5+
|| ()
6+
}
7+
8+
fn ff_debug() -> impl Fn() -> impl Fn() -> impl Debug {
9+
|| f_debug()
10+
}
11+
12+
fn main() {
13+
// Check that `ff_debug` is `() -> (() -> Debug)` and not `(() -> ()) -> Debug`
14+
let debug = ff_debug()()();
15+
assert_eq!(format!("{:?}", debug), "()");
16+
}

src/test/ui/impl-trait/nested_impl_trait.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> {
2525
}
2626

2727
fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
28-
//~^ `impl Trait` only allowed in function and inherent method return types
29-
|| 5
28+
|| 5u8
3029
}
3130

3231
fn main() {}

src/test/ui/impl-trait/nested_impl_trait.stderr

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,6 @@ error[E0562]: `impl Trait` only allowed in function and inherent method return t
4040
LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
4141
| ^^^^^^^^^^^^^^^^^^^^^
4242

43-
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
44-
--> $DIR/nested_impl_trait.rs:27:42
45-
|
46-
LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
47-
| ^^^^^^^^^^^^^^
48-
4943
error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
5044
--> $DIR/nested_impl_trait.rs:5:46
5145
|
@@ -64,7 +58,7 @@ LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
6458
= help: the trait `Into<U>` is implemented for `T`
6559
= note: required for `impl Into<u32>` to implement `Into<impl Debug>`
6660

67-
error: aborting due to 8 previous errors
61+
error: aborting due to 7 previous errors
6862

6963
Some errors have detailed explanations: E0277, E0562, E0666.
7064
For more information about an error, try `rustc --explain E0277`.

src/test/ui/impl-trait/where-allowed.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@ fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() }
3939
fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() }
4040
//~^ ERROR `impl Trait` only allowed in function and inherent method return types
4141

42-
// Disallowed
42+
// Allowed
4343
fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() }
44-
//~^ ERROR `impl Trait` only allowed in function and inherent method return types
4544

4645
// Disallowed
4746
fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() }
@@ -57,9 +56,8 @@ fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
5756
//~^ ERROR `impl Trait` only allowed in function and inherent method return types
5857
//~| ERROR nested `impl Trait` is not allowed
5958

60-
// Disallowed
59+
// Allowed
6160
fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
62-
//~^ ERROR `impl Trait` only allowed in function and inherent method return types
6361

6462
// Disallowed
6563
fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() }

0 commit comments

Comments
 (0)