Auto merge of #86215 - FabianWolff:unnameable-types, r=jackh726
Do not suggest to add type annotations for unnameable types Consider this example: ```rust const A = || 42; struct S<T> { t: T } const B: _ = S { t: || 42 }; ``` This currently produces the following output: ``` error: missing type for `const` item --> src/lib.rs:1:7 | 1 | const A = || 42; | ^ help: provide a type for the item: `A: [closure@src/lib.rs:1:11: 1:16]` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> src/lib.rs:4:10 | 4 | const B: _ = S { t: || 42 }; | ^ | | | not allowed in type signatures | help: replace `_` with the correct type: `S<[closure@src/lib.rs:4:21: 4:26]>` error: aborting due to 2 previous errors ``` However, these suggestions are obviously useless, because the suggested types cannot be written down. With my changes, the suggestion is replaced with a note, because there is no simple fix: ``` error: missing type for `const` item --> test.rs:1:7 | 1 | const A = || 42; | ^ | note: however, the inferred type `[closure@test.rs:1:11: 1:16]` cannot be named --> test.rs:1:11 | 1 | const A = || 42; | ^^^^^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> test.rs:4:10 | 4 | const B: _ = S { t: || 42 }; | ^ not allowed in type signatures | note: however, the inferred type `S<[closure@test.rs:4:21: 4:26]>` cannot be named --> test.rs:4:14 | 4 | const B: _ = S { t: || 42 }; | ^^^^^^^^^^^^^^ error: aborting due to 2 previous errors ```
This commit is contained in:
commit
60f1a2fc4b
@ -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,6 +749,40 @@ fn infer_placeholder_type(
|
||||
span: Span,
|
||||
item_ident: Ident,
|
||||
) -> Ty<'_> {
|
||||
// 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
|
||||
|
||||
// If this came from a free `const` or `static mut?` item,
|
||||
@ -760,24 +794,47 @@ fn infer_placeholder_type(
|
||||
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
|
||||
// We are typeck and have the real type, so remove that and suggest the actual type.
|
||||
err.suggestions.clear();
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"provide a type for the item",
|
||||
format!("{}: {}", item_ident, ty),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit_unless(ty.references_error());
|
||||
|
||||
// Suggesting unnameable types won't help.
|
||||
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, sugg_ty),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
err.span_note(
|
||||
tcx.hir().body(body_id).value.span,
|
||||
&format!("however, the inferred type `{}` cannot be named", ty.to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
err.emit_unless(ty.references_error());
|
||||
}
|
||||
None => {
|
||||
let mut diag = bad_placeholder_type(tcx, vec![span]);
|
||||
|
||||
if !ty.references_error() {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"replace with the correct type",
|
||||
ty.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
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",
|
||||
sugg_ty.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
diag.span_note(
|
||||
tcx.hir().body(body_id).value.span,
|
||||
&format!("however, the inferred type `{}` cannot be named", ty.to_string()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
|
39
src/test/ui/suggestions/unnamable-types.rs
Normal file
39
src/test/ui/suggestions/unnamable-types.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// Test that we do not suggest to add type annotations for unnamable types.
|
||||
|
||||
#![crate_type="lib"]
|
||||
#![feature(generators)]
|
||||
|
||||
const A = 5;
|
||||
//~^ ERROR: missing type for `const` item
|
||||
//~| HELP: provide a type for the item
|
||||
|
||||
static B: _ = "abc";
|
||||
//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
|
||||
//~| NOTE: not allowed in type signatures
|
||||
//~| 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: { let i = 0; move || -> i32 { i } } };
|
||||
//~^ ERROR: missing type for `const` item
|
||||
//~| NOTE: however, the inferred type
|
||||
|
||||
|
||||
fn foo() -> i32 { 42 }
|
||||
const E = foo;
|
||||
//~^ ERROR: missing type for `const` item
|
||||
//~| 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 G = || -> i32 { yield 0; return 1; };
|
||||
//~^ ERROR: missing type for `const` item
|
||||
//~| NOTE: however, the inferred type
|
66
src/test/ui/suggestions/unnamable-types.stderr
Normal file
66
src/test/ui/suggestions/unnamable-types.stderr
Normal file
@ -0,0 +1,66 @@
|
||||
error: missing type for `const` item
|
||||
--> $DIR/unnamable-types.rs:6:7
|
||||
|
|
||||
LL | const A = 5;
|
||||
| ^ help: provide a type for the item: `A: i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/unnamable-types.rs:10:11
|
||||
|
|
||||
LL | static B: _ = "abc";
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace with the correct type: `&str`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $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: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:23:7
|
||||
|
|
||||
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
|
||||
| ^
|
||||
|
|
||||
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: { let i = 0; move || -> i32 { i } } };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing type for `const` item
|
||||
--> $DIR/unnamable-types.rs:29:7
|
||||
|
|
||||
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 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:37:11: 37:43 {i32, ()}]` cannot be named
|
||||
--> $DIR/unnamable-types.rs:37:11
|
||||
|
|
||||
LL | const G = || -> i32 { yield 0; return 1; };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0121`.
|
Loading…
x
Reference in New Issue
Block a user