Skip to content

Commit

Permalink
hir_typeck: be more conservative in making "note caller chooses ty pa…
Browse files Browse the repository at this point in the history
…ram" 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: rust-lang#126547
  • Loading branch information
jieyouxu committed Jun 16, 2024
1 parent f6236f6 commit 964cb77
Showing 1 changed file with 25 additions and 12 deletions.
37 changes: 25 additions & 12 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -874,9 +874,9 @@ 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!("return type (hir::Ty) {:?}", hir_ty);
let ty = self.lowerer().lower_ty(hir_ty);
debug!("return type {:?}", ty);
debug!("return type (ty) {:?}", ty);
debug!("expected type {:?}", expected);
let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into());
let ty = Binder::bind_with_vars(ty, bound_vars);
Expand All @@ -888,7 +888,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, 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;
}
}
Expand All @@ -898,21 +898,34 @@ 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(
self.dcx(),
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(
self.dcx(),
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
Expand Down

0 comments on commit 964cb77

Please sign in to comment.