Rollup merge of #96377 - compiler-errors:infer-rustfix, r=petrochenkov
make `fn() -> _ { .. }` suggestion MachineApplicable
This might not be valid, but it would be nice to promote this to `MachineApplicable` so people can use rustfix here.
Also de65fcf009d07019689cfad7f327667e390a325d is to [restore the suggestion for `issue-77179.rs`](de65fcf009 (diff-12e43fb5d6d12ec7cb5c6b48204a18d113cf5de0e12eb71a358b639bd9aadaf0R8)
). (though in this case, the code in that issue still doesn't compile, so it's not marked with rustfix).
This commit is contained in:
commit
4a7483c905
5 changed files with 46 additions and 35 deletions
|
@ -3,8 +3,8 @@
|
|||
use crate::ty::subst::{GenericArg, GenericArgKind};
|
||||
use crate::ty::TyKind::*;
|
||||
use crate::ty::{
|
||||
ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
|
||||
ProjectionTy, Term, Ty, TyCtxt, TypeAndMut,
|
||||
ConstKind, DefIdTree, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef,
|
||||
InferTy, ProjectionTy, Term, Ty, TyCtxt, TypeAndMut,
|
||||
};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
@ -74,10 +74,10 @@ impl<'tcx> Ty<'tcx> {
|
|||
}
|
||||
|
||||
/// Whether the type can be safely suggested during error recovery.
|
||||
pub fn is_suggestable(self) -> bool {
|
||||
fn generic_arg_is_suggestible(arg: GenericArg<'_>) -> bool {
|
||||
pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||
fn generic_arg_is_suggestible<'tcx>(arg: GenericArg<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
|
||||
match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => ty.is_suggestable(),
|
||||
GenericArgKind::Type(ty) => ty.is_suggestable(tcx),
|
||||
GenericArgKind::Const(c) => const_is_suggestable(c.val()),
|
||||
_ => true,
|
||||
}
|
||||
|
@ -99,8 +99,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
// temporary, so I'll leave this as a fixme.
|
||||
|
||||
match self.kind() {
|
||||
Opaque(..)
|
||||
| FnDef(..)
|
||||
FnDef(..)
|
||||
| Closure(..)
|
||||
| Infer(..)
|
||||
| Generator(..)
|
||||
|
@ -108,27 +107,38 @@ impl<'tcx> Ty<'tcx> {
|
|||
| Bound(_, _)
|
||||
| Placeholder(_)
|
||||
| Error(_) => false,
|
||||
Opaque(did, substs) => {
|
||||
let parent = tcx.parent(*did).expect("opaque types always have a parent");
|
||||
if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = tcx.def_kind(parent)
|
||||
&& let Opaque(parent_did, _) = tcx.type_of(parent).kind()
|
||||
&& parent_did == did
|
||||
{
|
||||
substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() {
|
||||
ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
|
||||
substs.iter().all(generic_arg_is_suggestible)
|
||||
substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
|
||||
}
|
||||
ExistentialPredicate::Projection(ExistentialProjection {
|
||||
substs, term, ..
|
||||
}) => {
|
||||
let term_is_suggestable = match term {
|
||||
Term::Ty(ty) => ty.is_suggestable(),
|
||||
Term::Ty(ty) => ty.is_suggestable(tcx),
|
||||
Term::Const(c) => const_is_suggestable(c.val()),
|
||||
};
|
||||
term_is_suggestable && substs.iter().all(generic_arg_is_suggestible)
|
||||
term_is_suggestable && substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
|
||||
}
|
||||
_ => true,
|
||||
}),
|
||||
Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) => {
|
||||
args.iter().all(generic_arg_is_suggestible)
|
||||
args.iter().all(|a| generic_arg_is_suggestible(a, tcx))
|
||||
}
|
||||
Tuple(args) => args.iter().all(|ty| ty.is_suggestable()),
|
||||
Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(),
|
||||
Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val()),
|
||||
Tuple(args) => args.iter().all(|ty| ty.is_suggestable(tcx)),
|
||||
Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(tcx),
|
||||
Array(ty, c) => ty.is_suggestable(tcx) && const_is_suggestable(c.val()),
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let param_type = tcx.infer_ctxt().enter(|infcx| {
|
||||
infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
|
||||
});
|
||||
if param_type.is_suggestable() {
|
||||
if param_type.is_suggestable(tcx) {
|
||||
err.span_suggestion(
|
||||
tcx.def_span(src_def_id),
|
||||
"consider changing this type parameter to be a `const` generic",
|
||||
|
|
|
@ -2466,7 +2466,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
span,
|
||||
ty,
|
||||
opt_sugg: Some((span, Applicability::MachineApplicable))
|
||||
.filter(|_| ty.is_suggestable()),
|
||||
.filter(|_| ty.is_suggestable(tcx)),
|
||||
});
|
||||
|
||||
ty
|
||||
|
|
|
@ -525,7 +525,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
||||
// Only suggest changing the return type for methods that
|
||||
// haven't set a return type at all (and aren't `fn main()` or an impl).
|
||||
match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
|
||||
match (&fn_decl.output, found.is_suggestable(self.tcx), can_suggest, expected.is_unit()) {
|
||||
(&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
|
|
|
@ -41,7 +41,7 @@ use rustc_middle::ty::subst::InternalSubsts;
|
|||
use rustc_middle::ty::util::Discr;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{ReprOptions, ToPredicate, TypeFoldable};
|
||||
use rustc_middle::ty::{ReprOptions, ToPredicate};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
|
@ -2004,28 +2004,29 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
|||
visitor.visit_ty(ty);
|
||||
let mut diag = bad_placeholder(tcx, visitor.0, "return type");
|
||||
let ret_ty = fn_sig.skip_binder().output();
|
||||
if !ret_ty.references_error() {
|
||||
if !ret_ty.is_closure() {
|
||||
let ret_ty_str = match ret_ty.kind() {
|
||||
// Suggest a function pointer return type instead of a unique function definition
|
||||
// (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid
|
||||
// syntax)
|
||||
ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(),
|
||||
_ => ret_ty.to_string(),
|
||||
};
|
||||
if ret_ty.is_suggestable(tcx) {
|
||||
diag.span_suggestion(
|
||||
ty.span,
|
||||
"replace with the correct return type",
|
||||
ret_ty.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if matches!(ret_ty.kind(), ty::FnDef(..)) {
|
||||
let fn_sig = ret_ty.fn_sig(tcx);
|
||||
if fn_sig.skip_binder().inputs_and_output.iter().all(|t| t.is_suggestable(tcx)) {
|
||||
diag.span_suggestion(
|
||||
ty.span,
|
||||
"replace with the correct return type",
|
||||
ret_ty_str,
|
||||
Applicability::MaybeIncorrect,
|
||||
fn_sig.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
// We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
|
||||
// to prevent the user from getting a papercut while trying to use the unique closure
|
||||
// syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
|
||||
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
|
||||
diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
|
||||
}
|
||||
} else if ret_ty.is_closure() {
|
||||
// We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
|
||||
// to prevent the user from getting a papercut while trying to use the unique closure
|
||||
// syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
|
||||
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
|
||||
diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
|
||||
}
|
||||
diag.emit();
|
||||
|
||||
|
|
Loading…
Reference in a new issue