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 07dcf3876c806..4d29fc469462c 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 @@ -315,8 +315,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { body_id: Option, failure_span: Span, arg: GenericArg<'tcx>, - // FIXME(#94483): Either use this or remove it. - _impl_candidates: Vec>, error_code: TypeAnnotationNeeded, should_label_span: bool, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { @@ -534,6 +532,23 @@ enum InferSourceKind<'tcx> { }, } +impl<'tcx> InferSource<'tcx> { + fn from_expansion(&self) -> bool { + let source_from_expansion = match self.kind { + InferSourceKind::LetBinding { insert_span, .. } + | InferSourceKind::ClosureArg { insert_span, .. } + | InferSourceKind::GenericArg { insert_span, .. } => insert_span.from_expansion(), + InferSourceKind::FullyQualifiedMethodCall { receiver, .. } => { + receiver.span.from_expansion() + } + InferSourceKind::ClosureReturn { data, should_wrap_expr, .. } => { + data.span().from_expansion() || should_wrap_expr.map_or(false, Span::from_expansion) + } + }; + source_from_expansion || self.span.from_expansion() + } +} + impl<'tcx> InferSourceKind<'tcx> { fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String { match *self { @@ -604,43 +619,65 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { /// Sources with a small cost are prefer and should result /// in a clearer and idiomatic suggestion. fn source_cost(&self, source: &InferSource<'tcx>) -> usize { - let tcx = self.infcx.tcx; - - fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize { - match arg.unpack() { - GenericArgKind::Lifetime(_) => 0, // erased - GenericArgKind::Type(ty) => ty_cost(ty), - GenericArgKind::Const(_) => 3, // some non-zero value - } + #[derive(Clone, Copy)] + struct CostCtxt<'tcx> { + tcx: TyCtxt<'tcx>, } - fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize { - match ty.kind() { - ty::Closure(..) => 100, - ty::FnDef(..) => 20, - ty::FnPtr(..) => 10, - ty::Infer(..) => 0, - _ => 1, + impl<'tcx> CostCtxt<'tcx> { + fn arg_cost(self, arg: GenericArg<'tcx>) -> usize { + match arg.unpack() { + GenericArgKind::Lifetime(_) => 0, // erased + GenericArgKind::Type(ty) => self.ty_cost(ty), + GenericArgKind::Const(_) => 3, // some non-zero value + } + } + fn ty_cost(self, ty: Ty<'tcx>) -> usize { + match *ty.kind() { + ty::Closure(..) => 1000, + ty::FnDef(..) => 150, + ty::FnPtr(..) => 30, + ty::Adt(def, substs) => { + 5 + self + .tcx + .generics_of(def.did()) + .own_substs_no_defaults(self.tcx, substs) + .iter() + .map(|&arg| self.arg_cost(arg)) + .sum::() + } + ty::Tuple(args) => 5 + args.iter().map(|arg| self.ty_cost(arg)).sum::(), + ty::Ref(_, ty, _) => 2 + self.ty_cost(ty), + ty::Infer(..) => 0, + _ => 1, + } } } // The sources are listed in order of preference here. - match source.kind { - InferSourceKind::LetBinding { ty, .. } => ty_cost(ty), - InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty), + let tcx = self.infcx.tcx; + let ctx = CostCtxt { tcx }; + let base_cost = match source.kind { + InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty), + InferSourceKind::ClosureArg { ty, .. } => ctx.ty_cost(ty), InferSourceKind::GenericArg { def_id, generic_args, .. } => { let variant_cost = match tcx.def_kind(def_id) { - DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::` and friends are ugly. - _ => 12, + // `None::` and friends are ugly. + DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, + _ => 10, }; - variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::() + variant_cost + generic_args.iter().map(|&arg| ctx.arg_cost(arg)).sum::() } InferSourceKind::FullyQualifiedMethodCall { substs, .. } => { - 20 + substs.iter().map(|arg| arg_cost(arg)).sum::() + 20 + substs.iter().map(|arg| ctx.arg_cost(arg)).sum::() } InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => { - 30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 } + 30 + ctx.ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 } } - } + }; + + let suggestion_may_apply = if source.from_expansion() { 10000 } else { 0 }; + + base_cost + suggestion_may_apply } /// Uses `fn source_cost` to determine whether this inference source is preferable to @@ -648,6 +685,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn update_infer_source(&mut self, new_source: InferSource<'tcx>) { let cost = self.source_cost(&new_source) + self.attempt; + debug!(?cost); self.attempt += 1; if cost < self.infer_source_cost { self.infer_source_cost = cost; @@ -655,6 +693,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { } } + fn node_substs_opt(&self, hir_id: HirId) -> Option> { + let substs = self.typeck_results.node_substs_opt(hir_id); + self.infcx.resolve_vars_if_possible(substs) + } + fn opt_node_type(&self, hir_id: HirId) -> Option> { let ty = self.typeck_results.node_type_opt(hir_id); self.infcx.resolve_vars_if_possible(ty) @@ -737,7 +780,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { let tcx = self.infcx.tcx; match expr.kind { hir::ExprKind::Path(ref path) => { - if let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) { + if let Some(substs) = self.node_substs_opt(expr.hir_id) { return self.path_inferred_subst_iter(expr.hir_id, substs, path); } } @@ -765,7 +808,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { if generics.has_impl_trait() { None? } - let substs = self.typeck_results.node_substs_opt(expr.hir_id)?; + let substs = self.node_substs_opt(expr.hir_id)?; let span = tcx.hir().span(segment.hir_id?); let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); InsertableGenericArgs { @@ -980,8 +1023,10 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { debug!(?args); let InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } = args; let generics = tcx.generics_of(generics_def_id); - if let Some(argument_index) = - generics.own_substs(substs).iter().position(|&arg| self.generic_arg_is_target(arg)) + if let Some(argument_index) = generics + .own_substs(substs) + .iter() + .position(|&arg| self.generic_arg_contains_target(arg)) { let substs = self.infcx.resolve_vars_if_possible(substs); let generic_args = &generics.own_substs_no_defaults(tcx, substs) @@ -1037,7 +1082,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { .any(|generics| generics.has_impl_trait()) }; if let ExprKind::MethodCall(path, args, span) = expr.kind - && let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) + && let Some(substs) = self.node_substs_opt(expr.hir_id) && substs.iter().any(|arg| self.generic_arg_contains_target(arg)) && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) && self.infcx.tcx.trait_of_item(def_id).is_some() diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index fa56219b409d1..88b09f4de0a4c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1980,7 +1980,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { body_id, span, trait_ref.self_ty().skip_binder().into(), - vec![], ErrorCode::E0282, false, ) @@ -2005,19 +2004,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { let subst = data.trait_ref.substs.iter().find(|s| s.has_infer_types_or_consts()); let mut err = if let Some(subst) = subst { - let impl_candidates = self - .find_similar_impl_candidates(trait_ref) - .into_iter() - .map(|candidate| candidate.trait_ref) - .collect(); - self.emit_inference_failure_err( - body_id, - span, - subst, - impl_candidates, - ErrorCode::E0283, - true, - ) + self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true) } else { struct_span_err!( self.tcx.sess, @@ -2117,7 +2104,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { return; } - self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282, false) + self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282, false) } ty::PredicateKind::Subtype(data) => { @@ -2131,14 +2118,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { let SubtypePredicate { a_is_expected: _, a, b } = data; // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.emit_inference_failure_err( - body_id, - span, - a.into(), - vec![], - ErrorCode::E0282, - true, - ) + self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282, true) } ty::PredicateKind::Projection(data) => { if predicate.references_error() || self.is_tainted_by_errors() { @@ -2155,7 +2135,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { body_id, span, subst, - vec![], ErrorCode::E0284, true, ); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index bce2e85de845d..5297c48b4c37d 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1538,15 +1538,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } else { if !self.is_tainted_by_errors() { - self.emit_inference_failure_err( - (**self).body_id, - sp, - ty.into(), - vec![], - E0282, - true, - ) - .emit(); + self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true) + .emit(); } let err = self.tcx.ty_error(); self.demand_suptype(sp, err, ty); diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 67160b98b9dc0..16e5639096c5e 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -692,7 +692,6 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { Some(self.body.id()), self.span.to_span(self.tcx), t.into(), - vec![], E0282, false, ) @@ -707,7 +706,6 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { Some(self.body.id()), self.span.to_span(self.tcx), c.into(), - vec![], E0282, false, ) diff --git a/src/test/ui/inference/ambiguous_type_parameter.stderr b/src/test/ui/inference/ambiguous_type_parameter.stderr index a08342371b3b5..9cbe221de1393 100644 --- a/src/test/ui/inference/ambiguous_type_parameter.stderr +++ b/src/test/ui/inference/ambiguous_type_parameter.stderr @@ -2,7 +2,12 @@ error[E0282]: type annotations needed --> $DIR/ambiguous_type_parameter.rs:16:19 | LL | InMemoryStore.get_raw(&String::default()); - | ^^^^^^^ cannot infer type for type parameter `K` + | ^^^^^^^ + | +help: try using a fully qualified path to specify the expected types + | +LL | >>::get_raw(&InMemoryStore, &String::default()); + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ~ error: aborting due to previous error diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.rs b/src/test/ui/inference/cannot-infer-partial-try-return.rs index 976827a447860..b555697dc3461 100644 --- a/src/test/ui/inference/cannot-infer-partial-try-return.rs +++ b/src/test/ui/inference/cannot-infer-partial-try-return.rs @@ -16,8 +16,8 @@ fn infallible() -> Result<(), std::convert::Infallible> { fn main() { let x = || -> Result<_, QualifiedError<_>> { - //~^ ERROR type annotations needed for `Result<(), QualifiedError<_>>` infallible()?; Ok(()) + //~^ ERROR type annotations needed }; } diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.stderr b/src/test/ui/inference/cannot-infer-partial-try-return.stderr index c1e43f0b721f5..2a56aaa44fef2 100644 --- a/src/test/ui/inference/cannot-infer-partial-try-return.stderr +++ b/src/test/ui/inference/cannot-infer-partial-try-return.stderr @@ -1,16 +1,15 @@ -error[E0282]: type annotations needed for `Result<(), QualifiedError<_>>` - --> $DIR/cannot-infer-partial-try-return.rs:18:13 +error[E0282]: type annotations needed + --> $DIR/cannot-infer-partial-try-return.rs:20:9 | -LL | let x = || -> Result<_, QualifiedError<_>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | LL | infallible()?; | ------------- type must be known at this point +LL | Ok(()) + | ^^ cannot infer type of the type parameter `E` declared on the enum `Result` | -help: try giving this closure an explicit return type +help: consider specifying the generic arguments | -LL | let x = || -> Result<(), QualifiedError<_>> { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | Ok::<(), QualifiedError<_>>(()) + | +++++++++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/inference/need_type_info/channel.rs b/src/test/ui/inference/need_type_info/channel.rs new file mode 100644 index 0000000000000..e2ba5a9417138 --- /dev/null +++ b/src/test/ui/inference/need_type_info/channel.rs @@ -0,0 +1,19 @@ +// Test that we suggest specifying the generic argument of `channel` +// instead of the return type of that function, which is a lot more +// complex. +use std::sync::mpsc::channel; + +fn no_tuple() { + let _data = + channel(); //~ ERROR type annotations needed +} + +fn tuple() { + let (_sender, _receiver) = + channel(); //~ ERROR type annotations needed +} + +fn main() { + no_tuple(); + tuple(); +} diff --git a/src/test/ui/inference/need_type_info/channel.stderr b/src/test/ui/inference/need_type_info/channel.stderr new file mode 100644 index 0000000000000..e33ace0338d50 --- /dev/null +++ b/src/test/ui/inference/need_type_info/channel.stderr @@ -0,0 +1,25 @@ +error[E0282]: type annotations needed + --> $DIR/channel.rs:8:9 + | +LL | channel(); + | ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel` + | +help: consider specifying the generic argument + | +LL | channel::(); + | +++++ + +error[E0282]: type annotations needed + --> $DIR/channel.rs:13:9 + | +LL | channel(); + | ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel` + | +help: consider specifying the generic argument + | +LL | channel::(); + | +++++ + +error: aborting due to 2 previous errors + +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 401086b204435..7b9a1634a0d4c 100644 --- a/src/test/ui/issues/issue-23041.stderr +++ b/src/test/ui/issues/issue-23041.stderr @@ -1,8 +1,13 @@ error[E0282]: type annotations needed - --> $DIR/issue-23041.rs:6:22 + --> $DIR/issue-23041.rs:6:7 | LL | b.downcast_ref::_>(); - | ^^^^^^^^ cannot infer type + | ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref` + | +help: consider specifying the generic arguments + | +LL | b.downcast_ref:: _>(); + | ~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24013.stderr b/src/test/ui/issues/issue-24013.stderr index 4e3cb88297d3b..863993f450904 100644 --- a/src/test/ui/issues/issue-24013.stderr +++ b/src/test/ui/issues/issue-24013.stderr @@ -1,8 +1,13 @@ error[E0282]: type annotations needed - --> $DIR/issue-24013.rs:5:20 + --> $DIR/issue-24013.rs:5:13 | LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; - | ^^^^^^ cannot infer type + | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap` + | +help: consider specifying the generic arguments + | +LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; + | ~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25368.rs b/src/test/ui/issues/issue-25368.rs index b7f0f613e8091..4be83457f7a8b 100644 --- a/src/test/ui/issues/issue-25368.rs +++ b/src/test/ui/issues/issue-25368.rs @@ -5,10 +5,10 @@ use std::marker::PhantomData; struct Foo {foo: PhantomData} fn main() { - let (tx, rx) = //~ ERROR type annotations needed + let (tx, rx) = channel(); - // FIXME(#89862): Suggest adding a generic argument to `channel` instead spawn(move || { tx.send(Foo{ foo: PhantomData }); + //~^ ERROR type annotations needed }); } diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr index ffcb73849527f..e6ed3aac71032 100644 --- a/src/test/ui/issues/issue-25368.stderr +++ b/src/test/ui/issues/issue-25368.stderr @@ -1,13 +1,13 @@ -error[E0282]: type annotations needed for `(Sender>, std::sync::mpsc::Receiver>)` - --> $DIR/issue-25368.rs:8:9 +error[E0282]: type annotations needed + --> $DIR/issue-25368.rs:11:27 | -LL | let (tx, rx) = - | ^^^^^^^^ +LL | tx.send(Foo{ foo: PhantomData }); + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData` | -help: consider giving this pattern a type, where the type for type parameter `T` is specified +help: consider specifying the generic argument | -LL | let (tx, rx): (Sender>, std::sync::mpsc::Receiver>) = - | +++++++++++++++++++++++++++++++++++++++++++++++++++++ +LL | tx.send(Foo{ foo: PhantomData:: }); + | +++++ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index 66e7ada3ac5fd..e0f8a5447b081 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -13,7 +13,7 @@ error[E0283]: type annotations needed --> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7 | LL | x.foo(); - | ^^^ cannot infer type for struct `Vec<_>` + | ^^^ | note: multiple `impl`s satisfying `Vec<_>: Foo` found --> $DIR/method-ambig-one-trait-unknown-int-type.rs:9:1 @@ -23,6 +23,10 @@ LL | impl Foo for Vec { ... LL | impl Foo for Vec { | ^^^^^^^^^^^^^^^^^^^^^^^ +help: try using a fully qualified path to specify the expected types + | +LL | as Foo>::foo(&x); + | ++++++++++++++++++++++ ~ error[E0308]: mismatched types --> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20