Skip to content

Commit 60f1a2f

Browse files
committed
Auto merge of rust-lang#86215 - FabianWolff:unnameable-types, r=jackh726
Do not suggest to add type annotations for unnameable types Consider this example: ```rust const A = || 42; struct S<T> { t: T } const B: _ = S { t: || 42 }; ``` This currently produces the following output: ``` error: missing type for `const` item --> src/lib.rs:1:7 | 1 | const A = || 42; | ^ help: provide a type for the item: `A: [closure@src/lib.rs:1:11: 1:16]` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> src/lib.rs:4:10 | 4 | const B: _ = S { t: || 42 }; | ^ | | | not allowed in type signatures | help: replace `_` with the correct type: `S<[closure@src/lib.rs:4:21: 4:26]>` error: aborting due to 2 previous errors ``` However, these suggestions are obviously useless, because the suggested types cannot be written down. With my changes, the suggestion is replaced with a note, because there is no simple fix: ``` error: missing type for `const` item --> test.rs:1:7 | 1 | const A = || 42; | ^ | note: however, the inferred type `[[email protected]:1:11: 1:16]` cannot be named --> test.rs:1:11 | 1 | const A = || 42; | ^^^^^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> test.rs:4:10 | 4 | const B: _ = S { t: || 42 }; | ^ not allowed in type signatures | note: however, the inferred type `S<[[email protected]:4:21: 4:26]>` cannot be named --> test.rs:4:14 | 4 | const B: _ = S { t: || 42 }; | ^^^^^^^^^^^^^^ error: aborting due to 2 previous errors ```
2 parents d59b80d + 79dc9a7 commit 60f1a2f

File tree

3 files changed

+176
-14
lines changed

3 files changed

+176
-14
lines changed

compiler/rustc_typeck/src/collect/type_of.rs

+71-14
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,6 +749,40 @@ fn infer_placeholder_type(
749749
span: Span,
750750
item_ident: Ident,
751751
) -> Ty<'_> {
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
780+
}
781+
_ => ty.super_fold_with(self),
782+
}
783+
}
784+
}
785+
752786
let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
753787

754788
// If this came from a free `const` or `static mut?` item,
@@ -760,24 +794,47 @@ fn infer_placeholder_type(
760794
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
761795
// We are typeck and have the real type, so remove that and suggest the actual type.
762796
err.suggestions.clear();
763-
err.span_suggestion(
764-
span,
765-
"provide a type for the item",
766-
format!("{}: {}", item_ident, ty),
767-
Applicability::MachineApplicable,
768-
)
769-
.emit_unless(ty.references_error());
797+
798+
// Suggesting unnameable types won't help.
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 {
803+
err.span_suggestion(
804+
span,
805+
"provide a type for the item",
806+
format!("{}: {}", item_ident, sugg_ty),
807+
Applicability::MachineApplicable,
808+
);
809+
} else {
810+
err.span_note(
811+
tcx.hir().body(body_id).value.span,
812+
&format!("however, the inferred type `{}` cannot be named", ty.to_string()),
813+
);
814+
}
815+
816+
err.emit_unless(ty.references_error());
770817
}
771818
None => {
772819
let mut diag = bad_placeholder_type(tcx, vec![span]);
773820

774821
if !ty.references_error() {
775-
diag.span_suggestion(
776-
span,
777-
"replace with the correct type",
778-
ty.to_string(),
779-
Applicability::MaybeIncorrect,
780-
);
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 {
826+
diag.span_suggestion(
827+
span,
828+
"replace with the correct type",
829+
sugg_ty.to_string(),
830+
Applicability::MaybeIncorrect,
831+
);
832+
} else {
833+
diag.span_note(
834+
tcx.hir().body(body_id).value.span,
835+
&format!("however, the inferred type `{}` cannot be named", ty.to_string()),
836+
);
837+
}
781838
}
782839

783840
diag.emit();
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Test that we do not suggest to add type annotations for unnamable types.
2+
3+
#![crate_type="lib"]
4+
#![feature(generators)]
5+
6+
const A = 5;
7+
//~^ ERROR: missing type for `const` item
8+
//~| HELP: provide a type for the item
9+
10+
static B: _ = "abc";
11+
//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
12+
//~| NOTE: not allowed in type signatures
13+
//~| HELP: replace with the correct type
14+
15+
16+
// FIXME: this should also suggest a function pointer, as the closure is non-capturing
17+
const C: _ = || 42;
18+
//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
19+
//~| NOTE: not allowed in type signatures
20+
//~| NOTE: however, the inferred type
21+
22+
struct S<T> { t: T }
23+
const D = S { t: { let i = 0; move || -> i32 { i } } };
24+
//~^ ERROR: missing type for `const` item
25+
//~| NOTE: however, the inferred type
26+
27+
28+
fn foo() -> i32 { 42 }
29+
const E = foo;
30+
//~^ ERROR: missing type for `const` item
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+
36+
37+
const G = || -> i32 { yield 0; return 1; };
38+
//~^ ERROR: missing type for `const` item
39+
//~| NOTE: however, the inferred type
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
error: missing type for `const` item
2+
--> $DIR/unnamable-types.rs:6:7
3+
|
4+
LL | const A = 5;
5+
| ^ help: provide a type for the item: `A: i32`
6+
7+
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
8+
--> $DIR/unnamable-types.rs:10:11
9+
|
10+
LL | static B: _ = "abc";
11+
| ^
12+
| |
13+
| not allowed in type signatures
14+
| help: replace with the correct type: `&str`
15+
16+
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
17+
--> $DIR/unnamable-types.rs:17:10
18+
|
19+
LL | const C: _ = || 42;
20+
| ^ not allowed in type signatures
21+
|
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
24+
|
25+
LL | const C: _ = || 42;
26+
| ^^^^^
27+
28+
error: missing type for `const` item
29+
--> $DIR/unnamable-types.rs:23:7
30+
|
31+
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
32+
| ^
33+
|
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
36+
|
37+
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
39+
40+
error: missing type for `const` item
41+
--> $DIR/unnamable-types.rs:29:7
42+
|
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
48+
|
49+
LL | const F = S { t: foo };
50+
| ^ help: provide a type for the item: `F: S<fn() -> i32>`
51+
52+
error: missing type for `const` item
53+
--> $DIR/unnamable-types.rs:37:7
54+
|
55+
LL | const G = || -> i32 { yield 0; return 1; };
56+
| ^
57+
|
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
60+
|
61+
LL | const G = || -> i32 { yield 0; return 1; };
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63+
64+
error: aborting due to 7 previous errors
65+
66+
For more information about this error, try `rustc --explain E0121`.

0 commit comments

Comments
 (0)