From 469b7a916164d48a78d4bd8a10257bfe3b4a1dbe Mon Sep 17 00:00:00 2001 From: Denys Otrishko Date: Thu, 18 Jul 2019 18:41:59 +0300 Subject: [PATCH 1/4] rustc_typeck: improve diagnostics for _ const/static declarations --- src/librustc_typeck/check/mod.rs | 31 ++++++----- src/librustc_typeck/collect.rs | 53 ++++++++++++++++--- .../typeck_type_placeholder_item.stderr | 20 +++++-- 3 files changed, 80 insertions(+), 24 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bde6db78aef32..21cd4b694ae4c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -759,40 +759,40 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option { 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); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a5457c45d378c..053ef1f8f8297 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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 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 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 { 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) diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index ddaa5de4d3e27..2b4d9966c3d0b 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -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 From c6735a624b45f8170299c0539856c7d3b5f29422 Mon Sep 17 00:00:00 2001 From: Denys Otrishko Date: Fri, 19 Jul 2019 19:09:59 +0300 Subject: [PATCH 2/4] fixup! rustc_typeck: improve diagnostics for _ const/static declarations --- .../typeck_type_placeholder_item_help.rs | 18 +++++++++ .../typeck_type_placeholder_item_help.stderr | 38 ++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/test/ui/typeck/typeck_type_placeholder_item_help.rs b/src/test/ui/typeck/typeck_type_placeholder_item_help.rs index 5f4cb4c1316d5..905fc35350ed0 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item_help.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item_help.rs @@ -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 = test1(); let _: f64 = test1(); diff --git a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr index 7fb5549825cc5..c5b9566290c11 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr @@ -7,6 +7,42 @@ LL | fn test1() -> _ { Some(42) } | not allowed in type signatures | help: replace `_` with the correct return type: `std::option::Option` -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` + +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`. From b3618648f2d762c94bfbeee096562a799af38fe7 Mon Sep 17 00:00:00 2001 From: Denys Otrishko Date: Fri, 19 Jul 2019 21:59:54 +0300 Subject: [PATCH 3/4] fixup! rustc_typeck: improve diagnostics for _ const/static declarations --- src/test/ui/error-codes/E0121.stderr | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/ui/error-codes/E0121.stderr b/src/test/ui/error-codes/E0121.stderr index 1a16aab6a41d1..1def7029e6ed2 100644 --- a/src/test/ui/error-codes/E0121.stderr +++ b/src/test/ui/error-codes/E0121.stderr @@ -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 return type: `&'static str` error: aborting due to 2 previous errors From c6e027de52be7acd006e874500ac6a2095f888be Mon Sep 17 00:00:00 2001 From: Denys Otrishko Date: Fri, 19 Jul 2019 23:20:51 +0300 Subject: [PATCH 4/4] fixup! rustc_typeck: improve diagnostics for _ const/static declarations --- src/test/ui/error-codes/E0121.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/error-codes/E0121.stderr b/src/test/ui/error-codes/E0121.stderr index 1def7029e6ed2..beb8941320bc2 100644 --- a/src/test/ui/error-codes/E0121.stderr +++ b/src/test/ui/error-codes/E0121.stderr @@ -14,7 +14,7 @@ LL | static BAR: _ = "test"; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct return type: `&'static str` + | help: replace `_` with the correct type: `&'static str` error: aborting due to 2 previous errors