Rollup merge of #62804 - lundibundi:help-infer-const-static, r=eddyb
rustc_typeck: improve diagnostics for _ const/static declarations This continues https://github.com/rust-lang/rust/pull/62694 and adds type suggestions to const/static declarations with `_` type. r? @eddyb
This commit is contained in:
commit
13775d2304
@ -759,40 +759,40 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
|
||||
fn primary_body_of(
|
||||
tcx: TyCtxt<'_>,
|
||||
id: hir::HirId,
|
||||
) -> Option<(hir::BodyId, Option<&hir::FnHeader>, Option<&hir::FnDecl>)> {
|
||||
) -> Option<(hir::BodyId, Option<&hir::Ty>, Option<&hir::FnHeader>, Option<&hir::FnDecl>)> {
|
||||
match tcx.hir().get(id) {
|
||||
Node::Item(item) => {
|
||||
match item.node {
|
||||
hir::ItemKind::Const(_, body) |
|
||||
hir::ItemKind::Static(_, _, body) =>
|
||||
Some((body, None, None)),
|
||||
hir::ItemKind::Const(ref ty, body) |
|
||||
hir::ItemKind::Static(ref ty, _, body) =>
|
||||
Some((body, Some(ty), None, None)),
|
||||
hir::ItemKind::Fn(ref decl, ref header, .., body) =>
|
||||
Some((body, Some(header), Some(decl))),
|
||||
Some((body, None, Some(header), Some(decl))),
|
||||
_ =>
|
||||
None,
|
||||
}
|
||||
}
|
||||
Node::TraitItem(item) => {
|
||||
match item.node {
|
||||
hir::TraitItemKind::Const(_, Some(body)) =>
|
||||
Some((body, None, None)),
|
||||
hir::TraitItemKind::Const(ref ty, Some(body)) =>
|
||||
Some((body, Some(ty), None, None)),
|
||||
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) =>
|
||||
Some((body, Some(&sig.header), Some(&sig.decl))),
|
||||
Some((body, None, Some(&sig.header), Some(&sig.decl))),
|
||||
_ =>
|
||||
None,
|
||||
}
|
||||
}
|
||||
Node::ImplItem(item) => {
|
||||
match item.node {
|
||||
hir::ImplItemKind::Const(_, body) =>
|
||||
Some((body, None, None)),
|
||||
hir::ImplItemKind::Const(ref ty, body) =>
|
||||
Some((body, Some(ty), None, None)),
|
||||
hir::ImplItemKind::Method(ref sig, body) =>
|
||||
Some((body, Some(&sig.header), Some(&sig.decl))),
|
||||
Some((body, None, Some(&sig.header), Some(&sig.decl))),
|
||||
_ =>
|
||||
None,
|
||||
}
|
||||
}
|
||||
Node::AnonConst(constant) => Some((constant.body, None, None)),
|
||||
Node::AnonConst(constant) => Some((constant.body, None, None, None)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -825,7 +825,7 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
|
||||
let span = tcx.hir().span(id);
|
||||
|
||||
// Figure out what primary body this item has.
|
||||
let (body_id, fn_header, fn_decl) = primary_body_of(tcx, id)
|
||||
let (body_id, body_ty, fn_header, fn_decl) = primary_body_of(tcx, id)
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(span, "can't type-check body of {:?}", def_id);
|
||||
});
|
||||
@ -856,7 +856,10 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
|
||||
fcx
|
||||
} else {
|
||||
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
|
||||
let expected_type = tcx.type_of(def_id);
|
||||
let expected_type = body_ty.and_then(|ty| match ty.node {
|
||||
hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)),
|
||||
_ => None
|
||||
}).unwrap_or_else(|| tcx.type_of(def_id));
|
||||
let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
|
||||
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
|
||||
|
||||
|
@ -1135,6 +1135,26 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
||||
checked_type_of(tcx, def_id, true).unwrap()
|
||||
}
|
||||
|
||||
fn infer_placeholder_type(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
body_id: hir::BodyId,
|
||||
span: Span,
|
||||
) -> Ty<'_> {
|
||||
let ty = tcx.typeck_tables_of(def_id).node_type(body_id.hir_id);
|
||||
let mut diag = bad_placeholder_type(tcx, span);
|
||||
if ty != tcx.types.err {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"replace `_` with the correct type",
|
||||
ty.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
diag.emit();
|
||||
ty
|
||||
}
|
||||
|
||||
/// Same as [`type_of`] but returns [`Option`] instead of failing.
|
||||
///
|
||||
/// 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<
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
tcx.mk_fn_def(def_id, substs)
|
||||
}
|
||||
TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
|
||||
TraitItemKind::Const(ref ty, body_id) => {
|
||||
body_id.and_then(|body_id| {
|
||||
if let hir::TyKind::Infer = ty.node {
|
||||
Some(infer_placeholder_type(tcx, def_id, body_id, ty.span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).unwrap_or_else(|| icx.to_ty(ty))
|
||||
},
|
||||
TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
|
||||
TraitItemKind::Type(_, None) => {
|
||||
if !fail {
|
||||
return None;
|
||||
@ -1174,7 +1203,13 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
tcx.mk_fn_def(def_id, substs)
|
||||
}
|
||||
ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
|
||||
ImplItemKind::Const(ref ty, body_id) => {
|
||||
if let hir::TyKind::Infer = ty.node {
|
||||
infer_placeholder_type(tcx, def_id, body_id, ty.span)
|
||||
} else {
|
||||
icx.to_ty(ty)
|
||||
}
|
||||
},
|
||||
ImplItemKind::Existential(_) => {
|
||||
if tcx
|
||||
.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<
|
||||
|
||||
Node::Item(item) => {
|
||||
match item.node {
|
||||
ItemKind::Static(ref t, ..)
|
||||
| ItemKind::Const(ref t, _)
|
||||
| ItemKind::Ty(ref t, _)
|
||||
| ItemKind::Impl(.., ref t, _) => icx.to_ty(t),
|
||||
ItemKind::Static(ref ty, .., body_id)
|
||||
| ItemKind::Const(ref ty, body_id) => {
|
||||
if let hir::TyKind::Infer = ty.node {
|
||||
infer_placeholder_type(tcx, def_id, body_id, ty.span)
|
||||
} else {
|
||||
icx.to_ty(ty)
|
||||
}
|
||||
},
|
||||
ItemKind::Ty(ref ty, _)
|
||||
| ItemKind::Impl(.., ref ty, _) => icx.to_ty(ty),
|
||||
ItemKind::Fn(..) => {
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
tcx.mk_fn_def(def_id, substs)
|
||||
|
@ -11,7 +11,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
|
||||
--> $DIR/E0121.rs:3:13
|
||||
|
|
||||
LL | static BAR: _ = "test";
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct type: `&'static str`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -23,13 +23,19 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
|
||||
--> $DIR/typeck_type_placeholder_item.rs:11:15
|
||||
|
|
||||
LL | static TEST3: _ = "test";
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct type: `&'static str`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:14:15
|
||||
|
|
||||
LL | static TEST4: _ = 145;
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct type: `i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $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
|
||||
--> $DIR/typeck_type_placeholder_item.rs:64:22
|
||||
|
|
||||
LL | static FN_TEST3: _ = "test";
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct type: `&'static str`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:67:22
|
||||
|
|
||||
LL | static FN_TEST4: _ = 145;
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct type: `i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:70:23
|
||||
|
@ -4,6 +4,24 @@
|
||||
fn test1() -> _ { Some(42) }
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
|
||||
const TEST2: _ = 42u32;
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
|
||||
const TEST3: _ = Some(42);
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
|
||||
trait Test4 {
|
||||
const TEST4: _ = 42;
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
}
|
||||
|
||||
struct Test5;
|
||||
|
||||
impl Test5 {
|
||||
const TEST5: _ = 13;
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let _: Option<usize> = test1();
|
||||
let _: f64 = test1();
|
||||
|
@ -7,6 +7,42 @@ LL | fn test1() -> _ { Some(42) }
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct return type: `std::option::Option<i32>`
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item_help.rs:7:14
|
||||
|
|
||||
LL | const TEST2: _ = 42u32;
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct type: `u32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item_help.rs:10:14
|
||||
|
|
||||
LL | const TEST3: _ = Some(42);
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct type: `std::option::Option<i32>`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item_help.rs:14:18
|
||||
|
|
||||
LL | const TEST4: _ = 42;
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct type: `i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item_help.rs:21:18
|
||||
|
|
||||
LL | const TEST5: _ = 13;
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct type: `i32`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0121`.
|
||||
|
Loading…
Reference in New Issue
Block a user