Suggest a FnPtr type if a FnDef type is found

This commit is contained in:
Fabian Wolff 2021-06-11 20:12:40 +02:00
parent f687d5c43a
commit 79dc9a76a6
3 changed files with 74 additions and 39 deletions

View file

@ -9,7 +9,7 @@ use rustc_hir::{HirId, Node};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
@ -749,15 +749,38 @@ fn infer_placeholder_type(
span: Span,
item_ident: Ident,
) -> Ty<'_> {
fn contains_anonymous(ty: Ty<'_>) -> bool {
for gen_arg in ty.walk() {
if let ty::subst::GenericArgKind::Type(inner_ty) = gen_arg.unpack() {
if let ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) = inner_ty.kind() {
return true;
// Attempts to make the type nameable by turning FnDefs into FnPtrs.
struct MakeNameable<'tcx> {
success: bool,
tcx: TyCtxt<'tcx>,
}
impl<'tcx> MakeNameable<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> Self {
MakeNameable { success: true, tcx }
}
}
impl TypeFolder<'tcx> for MakeNameable<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if !self.success {
return ty;
}
match ty.kind() {
ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
// FIXME: non-capturing closures should also suggest a function pointer
ty::Closure(..) | ty::Generator(..) => {
self.success = false;
ty
}
_ => ty.super_fold_with(self),
}
}
false
}
let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
@ -773,11 +796,14 @@ fn infer_placeholder_type(
err.suggestions.clear();
// Suggesting unnameable types won't help.
if !contains_anonymous(ty) {
let mut mk_nameable = MakeNameable::new(tcx);
let ty = mk_nameable.fold_ty(ty);
let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
if let Some(sugg_ty) = sugg_ty {
err.span_suggestion(
span,
"provide a type for the item",
format!("{}: {}", item_ident, ty),
format!("{}: {}", item_ident, sugg_ty),
Applicability::MachineApplicable,
);
} else {
@ -793,11 +819,14 @@ fn infer_placeholder_type(
let mut diag = bad_placeholder_type(tcx, vec![span]);
if !ty.references_error() {
if !contains_anonymous(ty) {
let mut mk_nameable = MakeNameable::new(tcx);
let ty = mk_nameable.fold_ty(ty);
let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
if let Some(sugg_ty) = sugg_ty {
diag.span_suggestion(
span,
"replace with the correct type",
ty.to_string(),
sugg_ty.to_string(),
Applicability::MaybeIncorrect,
);
} else {

View file

@ -13,21 +13,27 @@ static B: _ = "abc";
//~| HELP: replace with the correct type
// FIXME: this should also suggest a function pointer, as the closure is non-capturing
const C: _ = || 42;
//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
//~| NOTE: not allowed in type signatures
//~| NOTE: however, the inferred type
struct S<T> { t: T }
const D = S { t: || -> i32 { 42 } };
const D = S { t: { let i = 0; move || -> i32 { i } } };
//~^ ERROR: missing type for `const` item
//~| NOTE: however, the inferred type
fn foo() -> i32 { 42 }
const E = S { t: foo };
const E = foo;
//~^ ERROR: missing type for `const` item
//~| NOTE: however, the inferred type
//~| HELP: provide a type for the item
const F = S { t: foo };
//~^ ERROR: missing type for `const` item
//~| HELP: provide a type for the item
const F = || -> i32 { yield 0; return 1; };
const G = || -> i32 { yield 0; return 1; };
//~^ ERROR: missing type for `const` item
//~| NOTE: however, the inferred type

View file

@ -14,53 +14,53 @@ LL | static B: _ = "abc";
| help: replace with the correct type: `&str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/unnamable-types.rs:16:10
--> $DIR/unnamable-types.rs:17:10
|
LL | const C: _ = || 42;
| ^ not allowed in type signatures
|
note: however, the inferred type `[closure@$DIR/unnamable-types.rs:16:14: 16:19]` cannot be named
--> $DIR/unnamable-types.rs:16:14
note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:19]` cannot be named
--> $DIR/unnamable-types.rs:17:14
|
LL | const C: _ = || 42;
| ^^^^^
error: missing type for `const` item
--> $DIR/unnamable-types.rs:22:7
--> $DIR/unnamable-types.rs:23:7
|
LL | const D = S { t: || -> i32 { 42 } };
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
| ^
|
note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:22:18: 22:34]>` cannot be named
--> $DIR/unnamable-types.rs:22:11
note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:51]>` cannot be named
--> $DIR/unnamable-types.rs:23:11
|
LL | const D = S { t: || -> i32 { 42 } };
| ^^^^^^^^^^^^^^^^^^^^^^^^^
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing type for `const` item
--> $DIR/unnamable-types.rs:27:7
--> $DIR/unnamable-types.rs:29:7
|
LL | const E = S { t: foo };
| ^
|
note: however, the inferred type `S<fn() -> i32 {foo}>` cannot be named
--> $DIR/unnamable-types.rs:27:11
|
LL | const E = S { t: foo };
| ^^^^^^^^^^^^
LL | const E = foo;
| ^ help: provide a type for the item: `E: fn() -> i32`
error: missing type for `const` item
--> $DIR/unnamable-types.rs:31:7
--> $DIR/unnamable-types.rs:32:7
|
LL | const F = || -> i32 { yield 0; return 1; };
LL | const F = S { t: foo };
| ^ help: provide a type for the item: `F: S<fn() -> i32>`
error: missing type for `const` item
--> $DIR/unnamable-types.rs:37:7
|
LL | const G = || -> i32 { yield 0; return 1; };
| ^
|
note: however, the inferred type `[generator@$DIR/unnamable-types.rs:31:11: 31:43 {i32, ()}]` cannot be named
--> $DIR/unnamable-types.rs:31:11
note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:43 {i32, ()}]` cannot be named
--> $DIR/unnamable-types.rs:37:11
|
LL | const F = || -> i32 { yield 0; return 1; };
LL | const G = || -> i32 { yield 0; return 1; };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0121`.