Skip to content

Commit f687d5c

Browse files
committed
Do not suggest to add type annotations for unnameable types
1 parent 66ba810 commit f687d5c

File tree

3 files changed

+140
-13
lines changed

3 files changed

+140
-13
lines changed

compiler/rustc_typeck/src/collect/type_of.rs

+41-13
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,17 @@ 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;
757+
}
758+
}
759+
}
760+
false
761+
}
762+
752763
let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
753764

754765
// If this came from a free `const` or `static mut?` item,
@@ -760,24 +771,41 @@ fn infer_placeholder_type(
760771
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
761772
// We are typeck and have the real type, so remove that and suggest the actual type.
762773
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());
774+
775+
// Suggesting unnameable types won't help.
776+
if !contains_anonymous(ty) {
777+
err.span_suggestion(
778+
span,
779+
"provide a type for the item",
780+
format!("{}: {}", item_ident, ty),
781+
Applicability::MachineApplicable,
782+
);
783+
} else {
784+
err.span_note(
785+
tcx.hir().body(body_id).value.span,
786+
&format!("however, the inferred type `{}` cannot be named", ty.to_string()),
787+
);
788+
}
789+
790+
err.emit_unless(ty.references_error());
770791
}
771792
None => {
772793
let mut diag = bad_placeholder_type(tcx, vec![span]);
773794

774795
if !ty.references_error() {
775-
diag.span_suggestion(
776-
span,
777-
"replace with the correct type",
778-
ty.to_string(),
779-
Applicability::MaybeIncorrect,
780-
);
796+
if !contains_anonymous(ty) {
797+
diag.span_suggestion(
798+
span,
799+
"replace with the correct type",
800+
ty.to_string(),
801+
Applicability::MaybeIncorrect,
802+
);
803+
} else {
804+
diag.span_note(
805+
tcx.hir().body(body_id).value.span,
806+
&format!("however, the inferred type `{}` cannot be named", ty.to_string()),
807+
);
808+
}
781809
}
782810

783811
diag.emit();
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
const C: _ = || 42;
17+
//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
18+
//~| NOTE: not allowed in type signatures
19+
//~| NOTE: however, the inferred type
20+
21+
struct S<T> { t: T }
22+
const D = S { t: || -> i32 { 42 } };
23+
//~^ ERROR: missing type for `const` item
24+
//~| NOTE: however, the inferred type
25+
26+
fn foo() -> i32 { 42 }
27+
const E = S { t: foo };
28+
//~^ ERROR: missing type for `const` item
29+
//~| NOTE: however, the inferred type
30+
31+
const F = || -> i32 { yield 0; return 1; };
32+
//~^ ERROR: missing type for `const` item
33+
//~| 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:16: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:16:14: 16:19]` cannot be named
23+
--> $DIR/unnamable-types.rs:16:14
24+
|
25+
LL | const C: _ = || 42;
26+
| ^^^^^
27+
28+
error: missing type for `const` item
29+
--> $DIR/unnamable-types.rs:22:7
30+
|
31+
LL | const D = S { t: || -> i32 { 42 } };
32+
| ^
33+
|
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
36+
|
37+
LL | const D = S { t: || -> i32 { 42 } };
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
39+
40+
error: missing type for `const` item
41+
--> $DIR/unnamable-types.rs:27:7
42+
|
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
48+
|
49+
LL | const E = S { t: foo };
50+
| ^^^^^^^^^^^^
51+
52+
error: missing type for `const` item
53+
--> $DIR/unnamable-types.rs:31:7
54+
|
55+
LL | const F = || -> i32 { yield 0; return 1; };
56+
| ^
57+
|
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
60+
|
61+
LL | const F = || -> i32 { yield 0; return 1; };
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63+
64+
error: aborting due to 6 previous errors
65+
66+
For more information about this error, try `rustc --explain E0121`.

0 commit comments

Comments
 (0)