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};
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);
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 {
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 {
//~| 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
| 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 = foo;
+ | ^ help: provide a type for the item: `E: fn() -> i32`
+
+error: missing type for `const` item
+ --> $DIR/unnamable-types.rs:32:7
|
-LL | const E = S { t: foo };
- | ^^^^^^^^^^^^
+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:31:7
+ --> $DIR/unnamable-types.rs:37:7
|
-LL | const F = || -> i32 { yield 0; return 1; };
+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`.