diff options
| author | 许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com> | 2024-06-18 21:05:25 +0000 |
|---|---|---|
| committer | 许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com> | 2024-06-18 21:05:59 +0000 |
| commit | bfe6a26af6669485b4661877583ebe3d22cd0317 (patch) | |
| tree | 88fd8fb6a68d8bef71ca285bc02f6f5ebc5d01d2 | |
| parent | dd104ef16315e2387fe94e8c43eb5a66e3dbd660 (diff) | |
| download | rust-bfe6a26af6669485b4661877583ebe3d22cd0317.tar.gz rust-bfe6a26af6669485b4661877583ebe3d22cd0317.zip | |
hir_typeck: be more conservative in making "note caller chooses ty param" note
- Avoid "caller chooses ty for type param" note if the found type a.k.a. the return expression type *contains* the type parameter, because e.g. `&T` will always be different from `T` (i.e. "well duh"). - Rename `note_caller_chooses_ty_for_ty_param` to `try_note_caller_chooses_ty_for_ty_param` because the note is not always made. Issue: https://github.com/rust-lang/rust/issues/126547
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 337a92c0d01..9dd82868adc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -859,10 +859,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Only point to return type if the expected type is the return type, as if they // are not, the expectation must have been caused by something else. - debug!("return type {:?}", hir_ty); + debug!(?hir_ty, "return type"); let ty = self.lowerer().lower_ty(hir_ty); - debug!("return type {:?}", ty); - debug!("expected type {:?}", expected); + debug!(?ty, "return type (lowered)"); + debug!(?expected, "expected type"); let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into()); let ty = Binder::bind_with_vars(ty, bound_vars); let ty = self.normalize(hir_ty.span, ty); @@ -873,7 +873,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected, }); self.try_suggest_return_impl_trait(err, expected, found, fn_id); - self.note_caller_chooses_ty_for_ty_param(err, expected, found); + self.try_note_caller_chooses_ty_for_ty_param(err, expected, found); return true; } } @@ -883,18 +883,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn note_caller_chooses_ty_for_ty_param( + fn try_note_caller_chooses_ty_for_ty_param( &self, diag: &mut Diag<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, ) { - if let ty::Param(expected_ty_as_param) = expected.kind() { - diag.subdiagnostic(errors::NoteCallerChoosesTyForTyParam { - ty_param_name: expected_ty_as_param.name, - found_ty: found, - }); + // Only show the note if: + // 1. `expected` ty is a type parameter; + // 2. The `expected` type parameter does *not* occur in the return expression type. This can + // happen for e.g. `fn foo<T>(t: &T) -> T { t }`, where `expected` is `T` but `found` is + // `&T`. Saying "the caller chooses a type for `T` which can be different from `&T`" is + // "well duh" and is only confusing and not helpful. + let ty::Param(expected_ty_as_param) = expected.kind() else { + return; + }; + + if found.contains(expected) { + return; } + + diag.subdiagnostic(errors::NoteCallerChoosesTyForTyParam { + ty_param_name: expected_ty_as_param.name, + found_ty: found, + }); } /// check whether the return type is a generic type with a trait bound |
