Skip to content

Commit 79dc9a7

Browse files
committed
Suggest a FnPtr type if a FnDef type is found
1 parent f687d5c commit 79dc9a7

File tree

3 files changed

+73
-38
lines changed

3 files changed

+73
-38
lines changed

compiler/rustc_typeck/src/collect/type_of.rs

+40-11
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_hir::{HirId, Node};
99
use rustc_middle::hir::map::Map;
1010
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
1111
use rustc_middle::ty::util::IntTypeExt;
12-
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
12+
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
1313
use rustc_span::symbol::Ident;
1414
use rustc_span::{Span, DUMMY_SP};
1515

@@ -749,15 +749,38 @@ fn infer_placeholder_type(
749749
span: Span,
750750
item_ident: Ident,
751751
) -> Ty<'_> {
752-
fn contains_anonymous(ty: Ty<'_>) -> bool {
753-
for gen_arg in ty.walk() {
754-
if let ty::subst::GenericArgKind::Type(inner_ty) = gen_arg.unpack() {
755-
if let ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) = inner_ty.kind() {
756-
return true;
752+
// Attempts to make the type nameable by turning FnDefs into FnPtrs.
753+
struct MakeNameable<'tcx> {
754+
success: bool,
755+
tcx: TyCtxt<'tcx>,
756+
}
757+
758+
impl<'tcx> MakeNameable<'tcx> {
759+
fn new(tcx: TyCtxt<'tcx>) -> Self {
760+
MakeNameable { success: true, tcx }
761+
}
762+
}
763+
764+
impl TypeFolder<'tcx> for MakeNameable<'tcx> {
765+
fn tcx(&self) -> TyCtxt<'tcx> {
766+
self.tcx
767+
}
768+
769+
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
770+
if !self.success {
771+
return ty;
772+
}
773+
774+
match ty.kind() {
775+
ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
776+
// FIXME: non-capturing closures should also suggest a function pointer
777+
ty::Closure(..) | ty::Generator(..) => {
778+
self.success = false;
779+
ty
757780
}
781+
_ => ty.super_fold_with(self),
758782
}
759783
}
760-
false
761784
}
762785

763786
let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
@@ -773,11 +796,14 @@ fn infer_placeholder_type(
773796
err.suggestions.clear();
774797

775798
// Suggesting unnameable types won't help.
776-
if !contains_anonymous(ty) {
799+
let mut mk_nameable = MakeNameable::new(tcx);
800+
let ty = mk_nameable.fold_ty(ty);
801+
let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
802+
if let Some(sugg_ty) = sugg_ty {
777803
err.span_suggestion(
778804
span,
779805
"provide a type for the item",
780-
format!("{}: {}", item_ident, ty),
806+
format!("{}: {}", item_ident, sugg_ty),
781807
Applicability::MachineApplicable,
782808
);
783809
} else {
@@ -793,11 +819,14 @@ fn infer_placeholder_type(
793819
let mut diag = bad_placeholder_type(tcx, vec![span]);
794820

795821
if !ty.references_error() {
796-
if !contains_anonymous(ty) {
822+
let mut mk_nameable = MakeNameable::new(tcx);
823+
let ty = mk_nameable.fold_ty(ty);
824+
let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
825+
if let Some(sugg_ty) = sugg_ty {
797826
diag.span_suggestion(
798827
span,
799828
"replace with the correct type",
800-
ty.to_string(),
829+
sugg_ty.to_string(),
801830
Applicability::MaybeIncorrect,
802831
);
803832
} else {

src/test/ui/suggestions/unnamable-types.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,27 @@ static B: _ = "abc";
1313
//~| HELP: replace with the correct type
1414

1515

16+
// FIXME: this should also suggest a function pointer, as the closure is non-capturing
1617
const C: _ = || 42;
1718
//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
1819
//~| NOTE: not allowed in type signatures
1920
//~| NOTE: however, the inferred type
2021

2122
struct S<T> { t: T }
22-
const D = S { t: || -> i32 { 42 } };
23+
const D = S { t: { let i = 0; move || -> i32 { i } } };
2324
//~^ ERROR: missing type for `const` item
2425
//~| NOTE: however, the inferred type
2526

27+
2628
fn foo() -> i32 { 42 }
27-
const E = S { t: foo };
29+
const E = foo;
2830
//~^ ERROR: missing type for `const` item
29-
//~| NOTE: however, the inferred type
31+
//~| HELP: provide a type for the item
32+
const F = S { t: foo };
33+
//~^ ERROR: missing type for `const` item
34+
//~| HELP: provide a type for the item
35+
3036

31-
const F = || -> i32 { yield 0; return 1; };
37+
const G = || -> i32 { yield 0; return 1; };
3238
//~^ ERROR: missing type for `const` item
3339
//~| NOTE: however, the inferred type

src/test/ui/suggestions/unnamable-types.stderr

+23-23
Original file line numberDiff line numberDiff line change
@@ -14,53 +14,53 @@ LL | static B: _ = "abc";
1414
| help: replace with the correct type: `&str`
1515

1616
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
17-
--> $DIR/unnamable-types.rs:16:10
17+
--> $DIR/unnamable-types.rs:17:10
1818
|
1919
LL | const C: _ = || 42;
2020
| ^ not allowed in type signatures
2121
|
22-
note: however, the inferred type `[closure@$DIR/unnamable-types.rs:16:14: 16:19]` cannot be named
23-
--> $DIR/unnamable-types.rs:16:14
22+
note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:19]` cannot be named
23+
--> $DIR/unnamable-types.rs:17:14
2424
|
2525
LL | const C: _ = || 42;
2626
| ^^^^^
2727

2828
error: missing type for `const` item
29-
--> $DIR/unnamable-types.rs:22:7
29+
--> $DIR/unnamable-types.rs:23:7
3030
|
31-
LL | const D = S { t: || -> i32 { 42 } };
31+
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
3232
| ^
3333
|
34-
note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:22:18: 22:34]>` cannot be named
35-
--> $DIR/unnamable-types.rs:22:11
34+
note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:51]>` cannot be named
35+
--> $DIR/unnamable-types.rs:23:11
3636
|
37-
LL | const D = S { t: || -> i32 { 42 } };
38-
| ^^^^^^^^^^^^^^^^^^^^^^^^^
37+
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3939

4040
error: missing type for `const` item
41-
--> $DIR/unnamable-types.rs:27:7
41+
--> $DIR/unnamable-types.rs:29:7
4242
|
43-
LL | const E = S { t: foo };
44-
| ^
45-
|
46-
note: however, the inferred type `S<fn() -> i32 {foo}>` cannot be named
47-
--> $DIR/unnamable-types.rs:27:11
43+
LL | const E = foo;
44+
| ^ help: provide a type for the item: `E: fn() -> i32`
45+
46+
error: missing type for `const` item
47+
--> $DIR/unnamable-types.rs:32:7
4848
|
49-
LL | const E = S { t: foo };
50-
| ^^^^^^^^^^^^
49+
LL | const F = S { t: foo };
50+
| ^ help: provide a type for the item: `F: S<fn() -> i32>`
5151

5252
error: missing type for `const` item
53-
--> $DIR/unnamable-types.rs:31:7
53+
--> $DIR/unnamable-types.rs:37:7
5454
|
55-
LL | const F = || -> i32 { yield 0; return 1; };
55+
LL | const G = || -> i32 { yield 0; return 1; };
5656
| ^
5757
|
58-
note: however, the inferred type `[generator@$DIR/unnamable-types.rs:31:11: 31:43 {i32, ()}]` cannot be named
59-
--> $DIR/unnamable-types.rs:31:11
58+
note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:43 {i32, ()}]` cannot be named
59+
--> $DIR/unnamable-types.rs:37:11
6060
|
61-
LL | const F = || -> i32 { yield 0; return 1; };
61+
LL | const G = || -> i32 { yield 0; return 1; };
6262
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6363

64-
error: aborting due to 6 previous errors
64+
error: aborting due to 7 previous errors
6565

6666
For more information about this error, try `rustc --explain E0121`.

0 commit comments

Comments
 (0)