X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=compiler%2Frustc_hir_typeck%2Fsrc%2Fdemand.rs;h=665dc8b6a2f2a4ed18091fb4952e550ca82ba30c;hb=b8f9cb345ab1401f2fbd14cc23f64dda9dd2314e;hp=f68a428d09ae3ba4b1d7f4e5043d7c0b71bc064c;hpb=eefc44b7e2e6657c7f0f214a0707aec83442c5c8;p=rust.git diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index f68a428d09a..665dc8b6a2f 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -85,6 +85,7 @@ pub fn emit_coerce_suggestions( self.note_internal_mutation_in_method(err, expr, expected, expr_ty); self.check_for_range_as_method_call(err, expr, expr_ty, expected); self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected); + self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty); } /// Requires that the two types unify, and prints an error message if @@ -303,11 +304,12 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { // Get the evaluated type *after* calling the method call, so that the influence // of the arguments can be reflected in the receiver type. The receiver // expression has the type *before* theis analysis is done. - let ty = match self.lookup_probe( + let ty = match self.lookup_probe_for_diagnostic( segment.ident, rcvr_ty, expr, probe::ProbeScope::TraitsInScope, + None, ) { Ok(pick) => pick.self_ty, Err(_) => rcvr_ty, @@ -557,19 +559,19 @@ fn annotate_alternative_method_deref( let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { return; }; let Ok(pick) = self - .probe_for_name( - probe::Mode::MethodCall, + .lookup_probe_for_diagnostic( path.ident, - probe::IsSuggestion(true), self_ty, - deref.hir_id, + deref, probe::ProbeScope::TraitsInScope, + None, ) else { return; }; let in_scope_methods = self.probe_for_name_many( probe::Mode::MethodCall, path.ident, + Some(expected), probe::IsSuggestion(true), self_ty, deref.hir_id, @@ -581,6 +583,7 @@ fn annotate_alternative_method_deref( let all_methods = self.probe_for_name_many( probe::Mode::MethodCall, path.ident, + Some(expected), probe::IsSuggestion(true), self_ty, deref.hir_id, @@ -1832,7 +1835,7 @@ pub fn check_for_cast( pub fn check_for_range_as_method_call( &self, err: &mut Diagnostic, - expr: &hir::Expr<'_>, + expr: &hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, ) { @@ -1850,10 +1853,14 @@ pub fn check_for_range_as_method_call( return; } let mut expr = end.expr; + let mut expectation = Some(expected_ty); while let hir::ExprKind::MethodCall(_, rcvr, ..) = expr.kind { // Getting to the root receiver and asserting it is a fn call let's us ignore cases in - // `src/test/ui/methods/issues/issue-90315.stderr`. + // `tests/ui/methods/issues/issue-90315.stderr`. expr = rcvr; + // If we have more than one layer of calls, then the expected ty + // cannot guide the method probe. + expectation = None; } let hir::ExprKind::Call(method_name, _) = expr.kind else { return; }; let ty::Adt(adt, _) = checked_ty.kind() else { return; }; @@ -1869,13 +1876,12 @@ pub fn check_for_range_as_method_call( let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else { return; }; let [hir::PathSegment { ident, .. }] = p.segments else { return; }; let self_ty = self.typeck_results.borrow().expr_ty(start.expr); - let Ok(_pick) = self.probe_for_name( - probe::Mode::MethodCall, + let Ok(_pick) = self.lookup_probe_for_diagnostic( *ident, - probe::IsSuggestion(true), self_ty, - expr.hir_id, + expr, probe::ProbeScope::AllTraits, + expectation, ) else { return; }; let mut sugg = "."; let mut span = start.expr.span.between(end.expr.span); @@ -1936,4 +1942,77 @@ fn check_for_binding_assigned_block_without_tail_expression( err.span_label(block.span, "this block is missing a tail expression"); } } + + fn check_wrong_return_type_due_to_generic_arg( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + checked_ty: Ty<'tcx>, + ) { + let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; }; + enum CallableKind { + Function, + Method, + Constructor, + } + let mut maybe_emit_help = |def_id: hir::def_id::DefId, + callable: rustc_span::symbol::Ident, + args: &[hir::Expr<'_>], + kind: CallableKind| { + let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap(); + let fn_ty = self.tcx.bound_type_of(def_id).0; + if !fn_ty.is_fn() { + return; + } + let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder(); + let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; }; + if matches!(arg.kind(), ty::Param(_)) + && fn_sig.output().contains(arg) + && self.node_ty(args[arg_idx].hir_id) == checked_ty + { + let mut multi_span: MultiSpan = parent_expr.span.into(); + multi_span.push_span_label( + args[arg_idx].span, + format!( + "this argument influences the {} of `{}`", + if matches!(kind, CallableKind::Constructor) { + "type" + } else { + "return type" + }, + callable + ), + ); + err.span_help( + multi_span, + format!( + "the {} `{}` due to the type of the argument passed", + match kind { + CallableKind::Function => "return type of this call is", + CallableKind::Method => "return type of this call is", + CallableKind::Constructor => "type constructed contains", + }, + checked_ty + ), + ); + } + }; + match parent_expr.kind { + hir::ExprKind::Call(fun, args) => { + let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; }; + let hir::def::Res::Def(kind, def_id) = path.res else { return; }; + let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) { + CallableKind::Constructor + } else { + CallableKind::Function + }; + maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind); + } + hir::ExprKind::MethodCall(method, _receiver, args, _span) => { + let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; }; + maybe_emit_help(def_id, method.ident, args, CallableKind::Method) + } + _ => return, + } + } }