Skip to content

Commit

Permalink
rustc_typeck: improve diagnostics for _ const/static declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
lundibundi committed Jul 19, 2019
1 parent 527dce7 commit 469b7a9
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 24 deletions.
31 changes: 17 additions & 14 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
Expand Down Expand Up @@ -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);
});
Expand Down Expand Up @@ -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);

Expand Down
53 changes: 47 additions & 6 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -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))
Expand All @@ -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)
Expand Down
20 changes: 16 additions & 4 deletions src/test/ui/typeck/typeck_type_placeholder_item.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 469b7a9

Please sign in to comment.