Skip to content

Commit 13775d2

Browse files
Rollup merge of #62804 - lundibundi:help-infer-const-static, r=eddyb
rustc_typeck: improve diagnostics for _ const/static declarations This continues #62694 and adds type suggestions to const/static declarations with `_` type. r? @eddyb
2 parents ab7149b + c6e027d commit 13775d2

File tree

6 files changed

+139
-26
lines changed

6 files changed

+139
-26
lines changed

src/librustc_typeck/check/mod.rs

+17-14
Original file line numberDiff line numberDiff line change
@@ -759,40 +759,40 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
759759
fn primary_body_of(
760760
tcx: TyCtxt<'_>,
761761
id: hir::HirId,
762-
) -> Option<(hir::BodyId, Option<&hir::FnHeader>, Option<&hir::FnDecl>)> {
762+
) -> Option<(hir::BodyId, Option<&hir::Ty>, Option<&hir::FnHeader>, Option<&hir::FnDecl>)> {
763763
match tcx.hir().get(id) {
764764
Node::Item(item) => {
765765
match item.node {
766-
hir::ItemKind::Const(_, body) |
767-
hir::ItemKind::Static(_, _, body) =>
768-
Some((body, None, None)),
766+
hir::ItemKind::Const(ref ty, body) |
767+
hir::ItemKind::Static(ref ty, _, body) =>
768+
Some((body, Some(ty), None, None)),
769769
hir::ItemKind::Fn(ref decl, ref header, .., body) =>
770-
Some((body, Some(header), Some(decl))),
770+
Some((body, None, Some(header), Some(decl))),
771771
_ =>
772772
None,
773773
}
774774
}
775775
Node::TraitItem(item) => {
776776
match item.node {
777-
hir::TraitItemKind::Const(_, Some(body)) =>
778-
Some((body, None, None)),
777+
hir::TraitItemKind::Const(ref ty, Some(body)) =>
778+
Some((body, Some(ty), None, None)),
779779
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) =>
780-
Some((body, Some(&sig.header), Some(&sig.decl))),
780+
Some((body, None, Some(&sig.header), Some(&sig.decl))),
781781
_ =>
782782
None,
783783
}
784784
}
785785
Node::ImplItem(item) => {
786786
match item.node {
787-
hir::ImplItemKind::Const(_, body) =>
788-
Some((body, None, None)),
787+
hir::ImplItemKind::Const(ref ty, body) =>
788+
Some((body, Some(ty), None, None)),
789789
hir::ImplItemKind::Method(ref sig, body) =>
790-
Some((body, Some(&sig.header), Some(&sig.decl))),
790+
Some((body, None, Some(&sig.header), Some(&sig.decl))),
791791
_ =>
792792
None,
793793
}
794794
}
795-
Node::AnonConst(constant) => Some((constant.body, None, None)),
795+
Node::AnonConst(constant) => Some((constant.body, None, None, None)),
796796
_ => None,
797797
}
798798
}
@@ -825,7 +825,7 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
825825
let span = tcx.hir().span(id);
826826

827827
// Figure out what primary body this item has.
828-
let (body_id, fn_header, fn_decl) = primary_body_of(tcx, id)
828+
let (body_id, body_ty, fn_header, fn_decl) = primary_body_of(tcx, id)
829829
.unwrap_or_else(|| {
830830
span_bug!(span, "can't type-check body of {:?}", def_id);
831831
});
@@ -856,7 +856,10 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
856856
fcx
857857
} else {
858858
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
859-
let expected_type = tcx.type_of(def_id);
859+
let expected_type = body_ty.and_then(|ty| match ty.node {
860+
hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)),
861+
_ => None
862+
}).unwrap_or_else(|| tcx.type_of(def_id));
860863
let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
861864
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
862865

src/librustc_typeck/collect.rs

+47-6
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,26 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
11351135
checked_type_of(tcx, def_id, true).unwrap()
11361136
}
11371137

1138+
fn infer_placeholder_type(
1139+
tcx: TyCtxt<'_>,
1140+
def_id: DefId,
1141+
body_id: hir::BodyId,
1142+
span: Span,
1143+
) -> Ty<'_> {
1144+
let ty = tcx.typeck_tables_of(def_id).node_type(body_id.hir_id);
1145+
let mut diag = bad_placeholder_type(tcx, span);
1146+
if ty != tcx.types.err {
1147+
diag.span_suggestion(
1148+
span,
1149+
"replace `_` with the correct type",
1150+
ty.to_string(),
1151+
Applicability::MaybeIncorrect,
1152+
);
1153+
}
1154+
diag.emit();
1155+
ty
1156+
}
1157+
11381158
/// Same as [`type_of`] but returns [`Option`] instead of failing.
11391159
///
11401160
/// If you want to fail anyway, you can set the `fail` parameter to true, but in this case,
@@ -1160,7 +1180,16 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
11601180
let substs = InternalSubsts::identity_for_item(tcx, def_id);
11611181
tcx.mk_fn_def(def_id, substs)
11621182
}
1163-
TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
1183+
TraitItemKind::Const(ref ty, body_id) => {
1184+
body_id.and_then(|body_id| {
1185+
if let hir::TyKind::Infer = ty.node {
1186+
Some(infer_placeholder_type(tcx, def_id, body_id, ty.span))
1187+
} else {
1188+
None
1189+
}
1190+
}).unwrap_or_else(|| icx.to_ty(ty))
1191+
},
1192+
TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
11641193
TraitItemKind::Type(_, None) => {
11651194
if !fail {
11661195
return None;
@@ -1174,7 +1203,13 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
11741203
let substs = InternalSubsts::identity_for_item(tcx, def_id);
11751204
tcx.mk_fn_def(def_id, substs)
11761205
}
1177-
ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
1206+
ImplItemKind::Const(ref ty, body_id) => {
1207+
if let hir::TyKind::Infer = ty.node {
1208+
infer_placeholder_type(tcx, def_id, body_id, ty.span)
1209+
} else {
1210+
icx.to_ty(ty)
1211+
}
1212+
},
11781213
ImplItemKind::Existential(_) => {
11791214
if tcx
11801215
.impl_trait_ref(tcx.hir().get_parent_did(hir_id))
@@ -1199,10 +1234,16 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
11991234

12001235
Node::Item(item) => {
12011236
match item.node {
1202-
ItemKind::Static(ref t, ..)
1203-
| ItemKind::Const(ref t, _)
1204-
| ItemKind::Ty(ref t, _)
1205-
| ItemKind::Impl(.., ref t, _) => icx.to_ty(t),
1237+
ItemKind::Static(ref ty, .., body_id)
1238+
| ItemKind::Const(ref ty, body_id) => {
1239+
if let hir::TyKind::Infer = ty.node {
1240+
infer_placeholder_type(tcx, def_id, body_id, ty.span)
1241+
} else {
1242+
icx.to_ty(ty)
1243+
}
1244+
},
1245+
ItemKind::Ty(ref ty, _)
1246+
| ItemKind::Impl(.., ref ty, _) => icx.to_ty(ty),
12061247
ItemKind::Fn(..) => {
12071248
let substs = InternalSubsts::identity_for_item(tcx, def_id);
12081249
tcx.mk_fn_def(def_id, substs)

src/test/ui/error-codes/E0121.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
1111
--> $DIR/E0121.rs:3:13
1212
|
1313
LL | static BAR: _ = "test";
14-
| ^ not allowed in type signatures
14+
| ^
15+
| |
16+
| not allowed in type signatures
17+
| help: replace `_` with the correct type: `&'static str`
1518

1619
error: aborting due to 2 previous errors
1720

src/test/ui/typeck/typeck_type_placeholder_item.stderr

+16-4
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,19 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
2323
--> $DIR/typeck_type_placeholder_item.rs:11:15
2424
|
2525
LL | static TEST3: _ = "test";
26-
| ^ not allowed in type signatures
26+
| ^
27+
| |
28+
| not allowed in type signatures
29+
| help: replace `_` with the correct type: `&'static str`
2730

2831
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
2932
--> $DIR/typeck_type_placeholder_item.rs:14:15
3033
|
3134
LL | static TEST4: _ = 145;
32-
| ^ not allowed in type signatures
35+
| ^
36+
| |
37+
| not allowed in type signatures
38+
| help: replace `_` with the correct type: `i32`
3339

3440
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
3541
--> $DIR/typeck_type_placeholder_item.rs:17:16
@@ -122,13 +128,19 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
122128
--> $DIR/typeck_type_placeholder_item.rs:64:22
123129
|
124130
LL | static FN_TEST3: _ = "test";
125-
| ^ not allowed in type signatures
131+
| ^
132+
| |
133+
| not allowed in type signatures
134+
| help: replace `_` with the correct type: `&'static str`
126135

127136
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
128137
--> $DIR/typeck_type_placeholder_item.rs:67:22
129138
|
130139
LL | static FN_TEST4: _ = 145;
131-
| ^ not allowed in type signatures
140+
| ^
141+
| |
142+
| not allowed in type signatures
143+
| help: replace `_` with the correct type: `i32`
132144

133145
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
134146
--> $DIR/typeck_type_placeholder_item.rs:70:23

src/test/ui/typeck/typeck_type_placeholder_item_help.rs

+18
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@
44
fn test1() -> _ { Some(42) }
55
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
66

7+
const TEST2: _ = 42u32;
8+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
9+
10+
const TEST3: _ = Some(42);
11+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
12+
13+
trait Test4 {
14+
const TEST4: _ = 42;
15+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
16+
}
17+
18+
struct Test5;
19+
20+
impl Test5 {
21+
const TEST5: _ = 13;
22+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
23+
}
24+
725
pub fn main() {
826
let _: Option<usize> = test1();
927
let _: f64 = test1();

src/test/ui/typeck/typeck_type_placeholder_item_help.stderr

+37-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,42 @@ LL | fn test1() -> _ { Some(42) }
77
| not allowed in type signatures
88
| help: replace `_` with the correct return type: `std::option::Option<i32>`
99

10-
error: aborting due to previous error
10+
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
11+
--> $DIR/typeck_type_placeholder_item_help.rs:7:14
12+
|
13+
LL | const TEST2: _ = 42u32;
14+
| ^
15+
| |
16+
| not allowed in type signatures
17+
| help: replace `_` with the correct type: `u32`
18+
19+
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
20+
--> $DIR/typeck_type_placeholder_item_help.rs:10:14
21+
|
22+
LL | const TEST3: _ = Some(42);
23+
| ^
24+
| |
25+
| not allowed in type signatures
26+
| help: replace `_` with the correct type: `std::option::Option<i32>`
27+
28+
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
29+
--> $DIR/typeck_type_placeholder_item_help.rs:14:18
30+
|
31+
LL | const TEST4: _ = 42;
32+
| ^
33+
| |
34+
| not allowed in type signatures
35+
| help: replace `_` with the correct type: `i32`
36+
37+
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
38+
--> $DIR/typeck_type_placeholder_item_help.rs:21:18
39+
|
40+
LL | const TEST5: _ = 13;
41+
| ^
42+
| |
43+
| not allowed in type signatures
44+
| help: replace `_` with the correct type: `i32`
45+
46+
error: aborting due to 5 previous errors
1147

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

0 commit comments

Comments
 (0)