diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index b267140daa9..561d1354edd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,4 +1,4 @@ -use crate::infer::type_variable::TypeVariableOriginKind; +use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; @@ -8,12 +8,12 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; use rustc_middle::hir::nested_filter; -use rustc_middle::infer::unify_key::ConstVariableOriginKind; +use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, InferConst}; -use rustc_middle::ty::{Ty, TyCtxt, TypeckResults}; +use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults}; use rustc_span::symbol::{kw, Ident}; use rustc_span::{BytePos, Span}; use std::borrow::Cow; @@ -407,11 +407,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label(span, cannot_infer_msg); - let printer = fmt_printer(self, Namespace::TypeNS); - let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer(); + let args = fmt_printer(self, Namespace::TypeNS) + .comma_sep(generic_args.iter().copied().map(|arg| { + if arg.is_suggestable(self.tcx, true) { + return arg; + } + + match arg.unpack() { + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + GenericArgKind::Type(_) => self + .next_ty_var(TypeVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: TypeVariableOriginKind::MiscVariable, + }) + .into(), + GenericArgKind::Const(arg) => self + .next_const_var( + arg.ty(), + ConstVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: ConstVariableOriginKind::MiscVariable, + }, + ) + .into(), + } + })) + .unwrap() + .into_buffer(); + err.span_suggestion_verbose( insert_span, - &format!("consider specifying the generic argument{}", pluralize!(args.len()),), + &format!( + "consider specifying the generic argument{}", + pluralize!(generic_args.len()), + ), format!("::<{}>", args), Applicability::HasPlaceholders, ); diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 25bc6dc6167..dd2f4321060 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use crate::ty::{ - visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, + visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, InferTy, PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; @@ -82,15 +82,18 @@ pub trait IsSuggestable<'tcx> { /// meaningful rendered suggestions when pretty-printed. We leave some /// nonsense, such as region vars, since those render as `'_` and are /// usually okay to reinterpret as elided lifetimes. - fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool; + /// + /// Only if `infer_suggestable` is true, we consider type and const + /// inference variables to be suggestable. + fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool; } impl<'tcx, T> IsSuggestable<'tcx> for T where T: TypeVisitable<'tcx>, { - fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool { - self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue() + fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool { + self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue() } } @@ -100,7 +103,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( err: &mut Diagnostic, trait_pred: PolyTraitPredicate<'tcx>, ) -> bool { - if !trait_pred.is_suggestable(tcx) { + if !trait_pred.is_suggestable(tcx, false) { return false; } @@ -419,6 +422,7 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { pub struct IsSuggestableVisitor<'tcx> { tcx: TyCtxt<'tcx>, + infer_suggestable: bool, } impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { @@ -426,6 +430,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { + Infer(InferTy::TyVar(_)) if self.infer_suggestable => {} + FnDef(..) | Closure(..) | Infer(..) @@ -479,6 +485,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow { match c.kind() { + ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {} + ConstKind::Infer(..) | ConstKind::Bound(..) | ConstKind::Placeholder(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5636c74452c..7ab85e7fa66 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -378,7 +378,7 @@ fn suggest_restriction<'tcx>( replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name)) .to_ty(tcx), }); - if !trait_pred.is_suggestable(tcx) { + if !trait_pred.is_suggestable(tcx, false) { return; } // We know we have an `impl Trait` that doesn't satisfy a required projection. @@ -417,7 +417,7 @@ fn suggest_restriction<'tcx>( Applicability::MaybeIncorrect, ); } else { - if !trait_pred.is_suggestable(tcx) { + if !trait_pred.is_suggestable(tcx, false) { return; } // Trivial case: `T` needs an extra bound: `T: Bound`. @@ -586,7 +586,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // else in the predicate. if !trait_pred.skip_binder().trait_ref.substs[1..] .iter() - .all(|g| g.is_suggestable(self.tcx)) + .all(|g| g.is_suggestable(self.tcx, false)) { return; } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 612dc384521..40aa27a29e9 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(tcx) { + if param_type.is_suggestable(tcx, false) { 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 9e4da058052..7111812f0b0 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2676,7 +2676,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, ty, opt_sugg: Some((span, Applicability::MachineApplicable)) - .filter(|_| ty.is_suggestable(tcx)), + .filter(|_| ty.is_suggestable(tcx, false)), }); ty diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 1555f4f3fd6..84d2878308a 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1070,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; if expected_ty.is_unit() { "()".to_string() - } else if expected_ty.is_suggestable(tcx) { + } else if expected_ty.is_suggestable(tcx, false) { format!("/* {} */", expected_ty) } else { "/* value */".to_string() diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 3e6ff72204f..097fff6418e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -506,7 +506,12 @@ 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(self.tcx), can_suggest, expected.is_unit()) { + match ( + &fn_decl.output, + found.is_suggestable(self.tcx, false), + can_suggest, + expected.is_unit(), + ) { (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found }); true diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 24e6a5d3047..c303905652d 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1929,7 +1929,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(tcx) { + if ret_ty.is_suggestable(tcx, false) { diag.span_suggestion( ty.span, "replace with the correct return type", @@ -1938,7 +1938,12 @@ 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(tcx)) { + if fn_sig + .skip_binder() + .inputs_and_output + .iter() + .all(|t| t.is_suggestable(tcx, false)) + { diag.span_suggestion( ty.span, "replace with the correct return type", diff --git a/src/test/ui/closures/issue-99565.rs b/src/test/ui/closures/issue-99565.rs new file mode 100644 index 00000000000..3a30d2ee034 --- /dev/null +++ b/src/test/ui/closures/issue-99565.rs @@ -0,0 +1,7 @@ +#![crate_type = "lib"] + +fn foo(_: U) {} + +fn bar() { + foo(|| {}); //~ ERROR type annotations needed +} diff --git a/src/test/ui/closures/issue-99565.stderr b/src/test/ui/closures/issue-99565.stderr new file mode 100644 index 00000000000..0d940aa9a2f --- /dev/null +++ b/src/test/ui/closures/issue-99565.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/issue-99565.rs:6:5 + | +LL | foo(|| {}); + | ^^^ cannot infer type of the type parameter `T` declared on the function `foo` + | +help: consider specifying the generic arguments + | +LL | foo::(|| {}); + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/issues/issue-23041.stderr b/src/test/ui/issues/issue-23041.stderr index 7b9a1634a0d..6592b76a39f 100644 --- a/src/test/ui/issues/issue-23041.stderr +++ b/src/test/ui/issues/issue-23041.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | b.downcast_ref::_>(); | ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref` | -help: consider specifying the generic arguments +help: consider specifying the generic argument | LL | b.downcast_ref:: _>(); | ~~~~~~~~~~~~~~ diff --git a/src/test/ui/issues/issue-24013.stderr b/src/test/ui/issues/issue-24013.stderr index 863993f4509..995dce552e3 100644 --- a/src/test/ui/issues/issue-24013.stderr +++ b/src/test/ui/issues/issue-24013.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap` | -help: consider specifying the generic arguments +help: consider specifying the generic argument | LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; | ~~~~~~~~~~