mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-27 14:24:08 +00:00
rustc_typeck: improve diagnostics for -> _ fn return type
Closes: https://github.com/rust-lang/rust/issues/56132
This commit is contained in:
parent
d9ad04a0f0
commit
f8681f0c05
@ -746,11 +746,12 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
|
||||
tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl)
|
||||
}
|
||||
|
||||
/// If this `DefId` is a "primary tables entry", returns `Some((body_id, decl))`
|
||||
/// with information about it's body-id and fn-decl (if any). Otherwise,
|
||||
/// If this `DefId` is a "primary tables entry", returns
|
||||
/// `Some((body_id, header, decl))` with information about
|
||||
/// it's body-id, fn-header and fn-decl (if any). Otherwise,
|
||||
/// returns `None`.
|
||||
///
|
||||
/// If this function returns "some", then `typeck_tables(def_id)` will
|
||||
/// If this function returns `Some`, then `typeck_tables(def_id)` will
|
||||
/// succeed; if it returns `None`, then `typeck_tables(def_id)` may or
|
||||
/// may not succeed. In some cases where this function returns `None`
|
||||
/// (notably closures), `typeck_tables(def_id)` would wind up
|
||||
@ -758,15 +759,15 @@ 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::FnDecl>)> {
|
||||
) -> Option<(hir::BodyId, 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)),
|
||||
hir::ItemKind::Fn(ref decl, .., body) =>
|
||||
Some((body, Some(decl))),
|
||||
Some((body, None, None)),
|
||||
hir::ItemKind::Fn(ref decl, ref header, .., body) =>
|
||||
Some((body, Some(header), Some(decl))),
|
||||
_ =>
|
||||
None,
|
||||
}
|
||||
@ -774,9 +775,9 @@ fn primary_body_of(
|
||||
Node::TraitItem(item) => {
|
||||
match item.node {
|
||||
hir::TraitItemKind::Const(_, Some(body)) =>
|
||||
Some((body, None)),
|
||||
Some((body, None, None)),
|
||||
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) =>
|
||||
Some((body, Some(&sig.decl))),
|
||||
Some((body, Some(&sig.header), Some(&sig.decl))),
|
||||
_ =>
|
||||
None,
|
||||
}
|
||||
@ -784,14 +785,14 @@ fn primary_body_of(
|
||||
Node::ImplItem(item) => {
|
||||
match item.node {
|
||||
hir::ImplItemKind::Const(_, body) =>
|
||||
Some((body, None)),
|
||||
Some((body, None, None)),
|
||||
hir::ImplItemKind::Method(ref sig, body) =>
|
||||
Some((body, Some(&sig.decl))),
|
||||
Some((body, Some(&sig.header), Some(&sig.decl))),
|
||||
_ =>
|
||||
None,
|
||||
}
|
||||
}
|
||||
Node::AnonConst(constant) => Some((constant.body, None)),
|
||||
Node::AnonConst(constant) => Some((constant.body, None, None)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -824,15 +825,21 @@ 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_decl) = primary_body_of(tcx, id).unwrap_or_else(|| {
|
||||
span_bug!(span, "can't type-check body of {:?}", def_id);
|
||||
});
|
||||
let (body_id, fn_header, fn_decl) = primary_body_of(tcx, id)
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(span, "can't type-check body of {:?}", def_id);
|
||||
});
|
||||
let body = tcx.hir().body(body_id);
|
||||
|
||||
let tables = Inherited::build(tcx, def_id).enter(|inh| {
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let fcx = if let Some(decl) = fn_decl {
|
||||
let fn_sig = tcx.fn_sig(def_id);
|
||||
let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) {
|
||||
let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
|
||||
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
|
||||
AstConv::ty_of_fn(&fcx, header.unsafety, header.abi, decl)
|
||||
} else {
|
||||
tcx.fn_sig(def_id)
|
||||
};
|
||||
|
||||
check_abi(tcx, span, fn_sig.abi());
|
||||
|
||||
|
@ -1682,6 +1682,15 @@ fn find_existential_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_infer_ret_ty(output: &'_ hir::FunctionRetTy) -> Option<&hir::Ty> {
|
||||
if let hir::FunctionRetTy::Return(ref ty) = output {
|
||||
if let hir::TyKind::Infer = ty.node {
|
||||
return Some(&**ty)
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
|
||||
use rustc::hir::*;
|
||||
use rustc::hir::Node::*;
|
||||
@ -1692,18 +1701,41 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
|
||||
|
||||
match tcx.hir().get(hir_id) {
|
||||
TraitItem(hir::TraitItem {
|
||||
node: TraitItemKind::Method(sig, _),
|
||||
node: TraitItemKind::Method(MethodSig { header, decl }, TraitMethod::Provided(_)),
|
||||
..
|
||||
})
|
||||
| ImplItem(hir::ImplItem {
|
||||
node: ImplItemKind::Method(sig, _),
|
||||
node: ImplItemKind::Method(MethodSig { header, decl }, _),
|
||||
..
|
||||
}) => AstConv::ty_of_fn(&icx, sig.header.unsafety, sig.header.abi, &sig.decl),
|
||||
|
||||
Item(hir::Item {
|
||||
})
|
||||
| Item(hir::Item {
|
||||
node: ItemKind::Fn(decl, header, _, _),
|
||||
..
|
||||
}) => AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl),
|
||||
}) => match get_infer_ret_ty(&decl.output) {
|
||||
Some(ty) => {
|
||||
let fn_sig = tcx.typeck_tables_of(def_id).liberated_fn_sigs()[hir_id];
|
||||
let mut diag = bad_placeholder_type(tcx, ty.span);
|
||||
let ret_ty = fn_sig.output();
|
||||
if ret_ty != tcx.types.err {
|
||||
diag.span_suggestion(
|
||||
ty.span,
|
||||
"replace `_` with the correct return type",
|
||||
ret_ty.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
diag.emit();
|
||||
ty::Binder::bind(fn_sig)
|
||||
},
|
||||
None => AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl)
|
||||
},
|
||||
|
||||
TraitItem(hir::TraitItem {
|
||||
node: TraitItemKind::Method(MethodSig { header, decl }, _),
|
||||
..
|
||||
}) => {
|
||||
AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl)
|
||||
},
|
||||
|
||||
ForeignItem(&hir::ForeignItem {
|
||||
node: ForeignItemKind::Fn(ref fn_decl, _, _),
|
||||
|
@ -2,7 +2,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
|
||||
--> $DIR/E0121.rs:1:13
|
||||
|
|
||||
LL | fn foo() -> _ { 5 }
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct return type: `i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/E0121.rs:3:13
|
||||
|
@ -2,7 +2,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
|
||||
--> $DIR/typeck_type_placeholder_item.rs:4:14
|
||||
|
|
||||
LL | fn test() -> _ { 5 }
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct return type: `i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:7:16
|
||||
@ -98,7 +101,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
|
||||
--> $DIR/typeck_type_placeholder_item.rs:57:21
|
||||
|
|
||||
LL | fn fn_test() -> _ { 5 }
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct return type: `i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:60:23
|
||||
@ -158,7 +164,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
|
||||
--> $DIR/typeck_type_placeholder_item.rs:33:24
|
||||
|
|
||||
LL | fn test9(&self) -> _ { () }
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct return type: `()`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:36:27
|
||||
@ -170,7 +179,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
|
||||
--> $DIR/typeck_type_placeholder_item.rs:41:24
|
||||
|
|
||||
LL | fn clone(&self) -> _ { Test9 }
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct return type: `Test9`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:44:37
|
||||
@ -182,7 +194,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
|
||||
--> $DIR/typeck_type_placeholder_item.rs:86:31
|
||||
|
|
||||
LL | fn fn_test9(&self) -> _ { () }
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct return type: `()`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:89:34
|
||||
@ -194,7 +209,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
|
||||
--> $DIR/typeck_type_placeholder_item.rs:94:28
|
||||
|
|
||||
LL | fn clone(&self) -> _ { FnTest9 }
|
||||
| ^ not allowed in type signatures
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace `_` with the correct return type: `main::FnTest9`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:97:41
|
||||
|
11
src/test/ui/typeck/typeck_type_placeholder_item_help.rs
Normal file
11
src/test/ui/typeck/typeck_type_placeholder_item_help.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// This test checks that it proper item type will be suggested when
|
||||
// using the `_` type placeholder.
|
||||
|
||||
fn test1() -> _ { Some(42) }
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
|
||||
pub fn main() {
|
||||
let _: Option<usize> = test1();
|
||||
let _: f64 = test1();
|
||||
let _: Option<i32> = test1();
|
||||
}
|
12
src/test/ui/typeck/typeck_type_placeholder_item_help.stderr
Normal file
12
src/test/ui/typeck/typeck_type_placeholder_item_help.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item_help.rs:4:15
|
||||
|
|
||||
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
|
||||
|
||||
For more information about this error, try `rustc --explain E0121`.
|
Loading…
Reference in New Issue
Block a user