|
1 | 1 | // ignore-tidy-filelength
|
2 | 2 |
|
3 | 3 | use super::{
|
4 |
| - DefIdOrName, FindExprBySpan, Obligation, ObligationCause, ObligationCauseCode, |
| 4 | + DefIdOrName, FindExprBySpan, ImplCandidate, Obligation, ObligationCause, ObligationCauseCode, |
5 | 5 | PredicateObligation,
|
6 | 6 | };
|
7 | 7 |
|
@@ -382,6 +382,14 @@ pub trait TypeErrCtxtExt<'tcx> {
|
382 | 382 | body_id: hir::HirId,
|
383 | 383 | param_env: ty::ParamEnv<'tcx>,
|
384 | 384 | ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>;
|
| 385 | + |
| 386 | + fn maybe_suggest_convert_to_slice( |
| 387 | + &self, |
| 388 | + err: &mut Diagnostic, |
| 389 | + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, |
| 390 | + candidate_impls: &[ImplCandidate<'tcx>], |
| 391 | + span: Span, |
| 392 | + ); |
385 | 393 | }
|
386 | 394 |
|
387 | 395 | fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
|
@@ -3826,6 +3834,73 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
3826 | 3834 | }
|
3827 | 3835 | assocs_in_this_method
|
3828 | 3836 | }
|
| 3837 | + |
| 3838 | + /// If the type that failed selection is an array or a reference to an array, |
| 3839 | + /// but the trait is implemented for slices, suggest that the user converts |
| 3840 | + /// the array into a slice. |
| 3841 | + fn maybe_suggest_convert_to_slice( |
| 3842 | + &self, |
| 3843 | + err: &mut Diagnostic, |
| 3844 | + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, |
| 3845 | + candidate_impls: &[ImplCandidate<'tcx>], |
| 3846 | + span: Span, |
| 3847 | + ) { |
| 3848 | + // Three cases where we can make a suggestion: |
| 3849 | + // 1. `[T; _]` (array of T) |
| 3850 | + // 2. `&[T; _]` (reference to array of T) |
| 3851 | + // 3. `&mut [T; _]` (mutable reference to array of T) |
| 3852 | + let (element_ty, mut mutability) = match *trait_ref.skip_binder().self_ty().kind() { |
| 3853 | + ty::Array(element_ty, _) => (element_ty, None), |
| 3854 | + |
| 3855 | + ty::Ref(_, pointee_ty, mutability) => match *pointee_ty.kind() { |
| 3856 | + ty::Array(element_ty, _) => (element_ty, Some(mutability)), |
| 3857 | + _ => return, |
| 3858 | + }, |
| 3859 | + |
| 3860 | + _ => return, |
| 3861 | + }; |
| 3862 | + |
| 3863 | + // Go through all the candidate impls to see if any of them is for |
| 3864 | + // slices of `element_ty` with `mutability`. |
| 3865 | + let mut is_slice = |candidate: Ty<'tcx>| match *candidate.kind() { |
| 3866 | + ty::RawPtr(ty::TypeAndMut { ty: t, mutbl: m }) | ty::Ref(_, t, m) => { |
| 3867 | + if matches!(*t.kind(), ty::Slice(e) if e == element_ty) |
| 3868 | + && m == mutability.unwrap_or(m) |
| 3869 | + { |
| 3870 | + // Use the candidate's mutability going forward. |
| 3871 | + mutability = Some(m); |
| 3872 | + true |
| 3873 | + } else { |
| 3874 | + false |
| 3875 | + } |
| 3876 | + } |
| 3877 | + _ => false, |
| 3878 | + }; |
| 3879 | + |
| 3880 | + // Grab the first candidate that matches, if any, and make a suggestion. |
| 3881 | + if let Some(slice_ty) = candidate_impls |
| 3882 | + .iter() |
| 3883 | + .map(|trait_ref| trait_ref.trait_ref.self_ty()) |
| 3884 | + .filter(|t| is_slice(*t)) |
| 3885 | + .next() |
| 3886 | + { |
| 3887 | + let msg = &format!("convert the array to a `{}` slice instead", slice_ty); |
| 3888 | + |
| 3889 | + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { |
| 3890 | + let mut suggestions = vec![]; |
| 3891 | + if snippet.starts_with('&') { |
| 3892 | + } else if let Some(hir::Mutability::Mut) = mutability { |
| 3893 | + suggestions.push((span.shrink_to_lo(), "&mut ".into())); |
| 3894 | + } else { |
| 3895 | + suggestions.push((span.shrink_to_lo(), "&".into())); |
| 3896 | + } |
| 3897 | + suggestions.push((span.shrink_to_hi(), "[..]".into())); |
| 3898 | + err.multipart_suggestion_verbose(msg, suggestions, Applicability::MaybeIncorrect); |
| 3899 | + } else { |
| 3900 | + err.span_help(span, msg); |
| 3901 | + } |
| 3902 | + } |
| 3903 | + } |
3829 | 3904 | }
|
3830 | 3905 |
|
3831 | 3906 | /// Add a hint to add a missing borrow or remove an unnecessary one.
|
|
0 commit comments