From ae42f22ba055337f802b02b8c07e999bd52ec01d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 24 Apr 2022 20:11:51 -0700 Subject: [PATCH 1/2] make `fn() -> _ {}` suggestion MachineApplicable --- compiler/rustc_typeck/src/collect.rs | 37 ++++++++++--------- .../type-alias-impl-trait/issue-77179.stderr | 5 +-- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index be77bdb0bf5..37bcbf37426 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -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() { + 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()) { 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(); diff --git a/src/test/ui/type-alias-impl-trait/issue-77179.stderr b/src/test/ui/type-alias-impl-trait/issue-77179.stderr index 053546e4b92..f9a1eaca384 100644 --- a/src/test/ui/type-alias-impl-trait/issue-77179.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-77179.stderr @@ -2,10 +2,7 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/issue-77179.rs:7:22 | LL | fn test() -> Pointer<_> { - | --------^- - | | | - | | not allowed in type signatures - | help: replace with the correct return type: `Pointer` + | ^ not allowed in type signatures error: aborting due to previous error From f9e7489f87f910c2ee87b7cf1052e368c1f191b6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 24 Apr 2022 20:41:37 -0700 Subject: [PATCH 2/2] TAITs are suggestable --- compiler/rustc_middle/src/ty/diagnostics.rs | 38 ++++++++++++------- compiler/rustc_typeck/src/astconv/generics.rs | 2 +- compiler/rustc_typeck/src/astconv/mod.rs | 2 +- .../src/check/fn_ctxt/suggestions.rs | 2 +- compiler/rustc_typeck/src/collect.rs | 4 +- .../type-alias-impl-trait/issue-77179.stderr | 5 ++- 6 files changed, 33 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 3b044b19259..8c8a2650fd6 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -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, } } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 5f5b81b8924..794e711b6c8 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -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", diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 1cd0ace8adb..4bf9e04480f 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -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 diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 62518408b8b..8db9da7fcb2 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -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, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 37bcbf37426..0ccc2b6b182 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2004,7 +2004,7 @@ 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.is_suggestable() { + if ret_ty.is_suggestable(tcx) { diag.span_suggestion( ty.span, "replace with the correct return type", @@ -2013,7 +2013,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( ); } 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()) { + 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", diff --git a/src/test/ui/type-alias-impl-trait/issue-77179.stderr b/src/test/ui/type-alias-impl-trait/issue-77179.stderr index f9a1eaca384..053546e4b92 100644 --- a/src/test/ui/type-alias-impl-trait/issue-77179.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-77179.stderr @@ -2,7 +2,10 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/issue-77179.rs:7:22 | LL | fn test() -> Pointer<_> { - | ^ not allowed in type signatures + | --------^- + | | | + | | not allowed in type signatures + | help: replace with the correct return type: `Pointer` error: aborting due to previous error