Skip to content

Commit f9477a7

Browse files
committed
Auto merge of #62694 - lundibundi:help-infer-fn-ret, r=eddyb
rustc_typeck: improve diagnostics for -> _ fn return type This should implement IIUC the mentioned issue. ~~I'm not sure if there is a better way than `get_infer_ret_ty` to get/check the return type without code duplication.~~ ~~Also, is this unwrap be okay `ty::Binder::bind(*tables.liberated_fn_sigs().get(hir_id).unwrap())`?~~ r? @eddyb Closes: #56132
2 parents fe499a7 + f8681f0 commit f9477a7

File tree

6 files changed

+125
-42
lines changed

6 files changed

+125
-42
lines changed

src/librustc_typeck/check/mod.rs

+24-17
Original file line numberDiff line numberDiff line change
@@ -746,52 +746,53 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
746746
tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl)
747747
}
748748

749-
/// If this `DefId` is a "primary tables entry", returns `Some((body_id, decl))`
750-
/// with information about it's body-id and fn-decl (if any). Otherwise,
749+
/// If this `DefId` is a "primary tables entry", returns
750+
/// `Some((body_id, header, decl))` with information about
751+
/// it's body-id, fn-header and fn-decl (if any). Otherwise,
751752
/// returns `None`.
752753
///
753-
/// If this function returns "some", then `typeck_tables(def_id)` will
754+
/// If this function returns `Some`, then `typeck_tables(def_id)` will
754755
/// succeed; if it returns `None`, then `typeck_tables(def_id)` may or
755756
/// may not succeed. In some cases where this function returns `None`
756757
/// (notably closures), `typeck_tables(def_id)` would wind up
757758
/// redirecting to the owning function.
758759
fn primary_body_of(
759760
tcx: TyCtxt<'_>,
760761
id: hir::HirId,
761-
) -> Option<(hir::BodyId, Option<&hir::FnDecl>)> {
762+
) -> Option<(hir::BodyId, Option<&hir::FnHeader>, Option<&hir::FnDecl>)> {
762763
match tcx.hir().get(id) {
763764
Node::Item(item) => {
764765
match item.node {
765766
hir::ItemKind::Const(_, body) |
766767
hir::ItemKind::Static(_, _, body) =>
767-
Some((body, None)),
768-
hir::ItemKind::Fn(ref decl, .., body) =>
769-
Some((body, Some(decl))),
768+
Some((body, None, None)),
769+
hir::ItemKind::Fn(ref decl, ref header, .., body) =>
770+
Some((body, Some(header), Some(decl))),
770771
_ =>
771772
None,
772773
}
773774
}
774775
Node::TraitItem(item) => {
775776
match item.node {
776777
hir::TraitItemKind::Const(_, Some(body)) =>
777-
Some((body, None)),
778+
Some((body, None, None)),
778779
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) =>
779-
Some((body, Some(&sig.decl))),
780+
Some((body, Some(&sig.header), Some(&sig.decl))),
780781
_ =>
781782
None,
782783
}
783784
}
784785
Node::ImplItem(item) => {
785786
match item.node {
786787
hir::ImplItemKind::Const(_, body) =>
787-
Some((body, None)),
788+
Some((body, None, None)),
788789
hir::ImplItemKind::Method(ref sig, body) =>
789-
Some((body, Some(&sig.decl))),
790+
Some((body, Some(&sig.header), Some(&sig.decl))),
790791
_ =>
791792
None,
792793
}
793794
}
794-
Node::AnonConst(constant) => Some((constant.body, None)),
795+
Node::AnonConst(constant) => Some((constant.body, None, None)),
795796
_ => None,
796797
}
797798
}
@@ -824,15 +825,21 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
824825
let span = tcx.hir().span(id);
825826

826827
// Figure out what primary body this item has.
827-
let (body_id, fn_decl) = primary_body_of(tcx, id).unwrap_or_else(|| {
828-
span_bug!(span, "can't type-check body of {:?}", def_id);
829-
});
828+
let (body_id, fn_header, fn_decl) = primary_body_of(tcx, id)
829+
.unwrap_or_else(|| {
830+
span_bug!(span, "can't type-check body of {:?}", def_id);
831+
});
830832
let body = tcx.hir().body(body_id);
831833

832834
let tables = Inherited::build(tcx, def_id).enter(|inh| {
833835
let param_env = tcx.param_env(def_id);
834-
let fcx = if let Some(decl) = fn_decl {
835-
let fn_sig = tcx.fn_sig(def_id);
836+
let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) {
837+
let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
838+
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
839+
AstConv::ty_of_fn(&fcx, header.unsafety, header.abi, decl)
840+
} else {
841+
tcx.fn_sig(def_id)
842+
};
836843

837844
check_abi(tcx, span, fn_sig.abi());
838845

src/librustc_typeck/collect.rs

+50-18
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,16 @@ impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
160160
///////////////////////////////////////////////////////////////////////////
161161
// Utility types and common code for the above passes.
162162

163+
fn bad_placeholder_type(tcx: TyCtxt<'tcx>, span: Span) -> errors::DiagnosticBuilder<'tcx> {
164+
let mut diag = tcx.sess.struct_span_err_with_code(
165+
span,
166+
"the type placeholder `_` is not allowed within types on item signatures",
167+
DiagnosticId::Error("E0121".into()),
168+
);
169+
diag.span_label(span, "not allowed in type signatures");
170+
diag
171+
}
172+
163173
impl ItemCtxt<'tcx> {
164174
pub fn new(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> ItemCtxt<'tcx> {
165175
ItemCtxt { tcx, item_def_id }
@@ -191,12 +201,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
191201
}
192202

193203
fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
194-
self.tcx().sess.struct_span_err_with_code(
195-
span,
196-
"the type placeholder `_` is not allowed within types on item signatures",
197-
DiagnosticId::Error("E0121".into()),
198-
).span_label(span, "not allowed in type signatures")
199-
.emit();
204+
bad_placeholder_type(self.tcx(), span).emit();
200205

201206
self.tcx().types.err
202207
}
@@ -207,12 +212,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
207212
_: Option<&ty::GenericParamDef>,
208213
span: Span,
209214
) -> &'tcx Const<'tcx> {
210-
self.tcx().sess.struct_span_err_with_code(
211-
span,
212-
"the const placeholder `_` is not allowed within types on item signatures",
213-
DiagnosticId::Error("E0121".into()),
214-
).span_label(span, "not allowed in type signatures")
215-
.emit();
215+
bad_placeholder_type(self.tcx(), span).emit();
216216

217217
self.tcx().consts.err
218218
}
@@ -1682,6 +1682,15 @@ fn find_existential_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
16821682
}
16831683
}
16841684

1685+
pub fn get_infer_ret_ty(output: &'_ hir::FunctionRetTy) -> Option<&hir::Ty> {
1686+
if let hir::FunctionRetTy::Return(ref ty) = output {
1687+
if let hir::TyKind::Infer = ty.node {
1688+
return Some(&**ty)
1689+
}
1690+
}
1691+
None
1692+
}
1693+
16851694
fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
16861695
use rustc::hir::*;
16871696
use rustc::hir::Node::*;
@@ -1692,18 +1701,41 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
16921701

16931702
match tcx.hir().get(hir_id) {
16941703
TraitItem(hir::TraitItem {
1695-
node: TraitItemKind::Method(sig, _),
1704+
node: TraitItemKind::Method(MethodSig { header, decl }, TraitMethod::Provided(_)),
16961705
..
16971706
})
16981707
| ImplItem(hir::ImplItem {
1699-
node: ImplItemKind::Method(sig, _),
1708+
node: ImplItemKind::Method(MethodSig { header, decl }, _),
17001709
..
1701-
}) => AstConv::ty_of_fn(&icx, sig.header.unsafety, sig.header.abi, &sig.decl),
1702-
1703-
Item(hir::Item {
1710+
})
1711+
| Item(hir::Item {
17041712
node: ItemKind::Fn(decl, header, _, _),
17051713
..
1706-
}) => AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl),
1714+
}) => match get_infer_ret_ty(&decl.output) {
1715+
Some(ty) => {
1716+
let fn_sig = tcx.typeck_tables_of(def_id).liberated_fn_sigs()[hir_id];
1717+
let mut diag = bad_placeholder_type(tcx, ty.span);
1718+
let ret_ty = fn_sig.output();
1719+
if ret_ty != tcx.types.err {
1720+
diag.span_suggestion(
1721+
ty.span,
1722+
"replace `_` with the correct return type",
1723+
ret_ty.to_string(),
1724+
Applicability::MaybeIncorrect,
1725+
);
1726+
}
1727+
diag.emit();
1728+
ty::Binder::bind(fn_sig)
1729+
},
1730+
None => AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl)
1731+
},
1732+
1733+
TraitItem(hir::TraitItem {
1734+
node: TraitItemKind::Method(MethodSig { header, decl }, _),
1735+
..
1736+
}) => {
1737+
AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl)
1738+
},
17071739

17081740
ForeignItem(&hir::ForeignItem {
17091741
node: ForeignItemKind::Fn(ref fn_decl, _, _),

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
22
--> $DIR/E0121.rs:1:13
33
|
44
LL | fn foo() -> _ { 5 }
5-
| ^ not allowed in type signatures
5+
| ^
6+
| |
7+
| not allowed in type signatures
8+
| help: replace `_` with the correct return type: `i32`
69

710
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
811
--> $DIR/E0121.rs:3:13

src/test/ui/typeck/typeck_type_placeholder_item.stderr

+24-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
22
--> $DIR/typeck_type_placeholder_item.rs:4:14
33
|
44
LL | fn test() -> _ { 5 }
5-
| ^ not allowed in type signatures
5+
| ^
6+
| |
7+
| not allowed in type signatures
8+
| help: replace `_` with the correct return type: `i32`
69

710
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
811
--> $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
98101
--> $DIR/typeck_type_placeholder_item.rs:57:21
99102
|
100103
LL | fn fn_test() -> _ { 5 }
101-
| ^ not allowed in type signatures
104+
| ^
105+
| |
106+
| not allowed in type signatures
107+
| help: replace `_` with the correct return type: `i32`
102108

103109
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
104110
--> $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
158164
--> $DIR/typeck_type_placeholder_item.rs:33:24
159165
|
160166
LL | fn test9(&self) -> _ { () }
161-
| ^ not allowed in type signatures
167+
| ^
168+
| |
169+
| not allowed in type signatures
170+
| help: replace `_` with the correct return type: `()`
162171

163172
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
164173
--> $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
170179
--> $DIR/typeck_type_placeholder_item.rs:41:24
171180
|
172181
LL | fn clone(&self) -> _ { Test9 }
173-
| ^ not allowed in type signatures
182+
| ^
183+
| |
184+
| not allowed in type signatures
185+
| help: replace `_` with the correct return type: `Test9`
174186

175187
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
176188
--> $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
182194
--> $DIR/typeck_type_placeholder_item.rs:86:31
183195
|
184196
LL | fn fn_test9(&self) -> _ { () }
185-
| ^ not allowed in type signatures
197+
| ^
198+
| |
199+
| not allowed in type signatures
200+
| help: replace `_` with the correct return type: `()`
186201

187202
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
188203
--> $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
194209
--> $DIR/typeck_type_placeholder_item.rs:94:28
195210
|
196211
LL | fn clone(&self) -> _ { FnTest9 }
197-
| ^ not allowed in type signatures
212+
| ^
213+
| |
214+
| not allowed in type signatures
215+
| help: replace `_` with the correct return type: `main::FnTest9`
198216

199217
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
200218
--> $DIR/typeck_type_placeholder_item.rs:97:41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// This test checks that it proper item type will be suggested when
2+
// using the `_` type placeholder.
3+
4+
fn test1() -> _ { Some(42) }
5+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
6+
7+
pub fn main() {
8+
let _: Option<usize> = test1();
9+
let _: f64 = test1();
10+
let _: Option<i32> = test1();
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
2+
--> $DIR/typeck_type_placeholder_item_help.rs:4:15
3+
|
4+
LL | fn test1() -> _ { Some(42) }
5+
| ^
6+
| |
7+
| not allowed in type signatures
8+
| help: replace `_` with the correct return type: `std::option::Option<i32>`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0121`.

0 commit comments

Comments
 (0)