@@ -777,19 +777,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
777
777
} else {
778
778
"items from traits can only be used if the trait is implemented and in scope"
779
779
});
780
- let mut msg = format!(
780
+ let message = |action| format!(
781
781
"the following {traits_define} an item `{name}`, perhaps you need to {action} \
782
782
{one_of_them}:",
783
783
traits_define = if candidates.len() == 1 {
784
784
"trait defines"
785
785
} else {
786
786
"traits define"
787
787
},
788
- action = if let Some(param) = param_type {
789
- format!("restrict type parameter `{}` with", param)
790
- } else {
791
- "implement".to_string()
792
- },
788
+ action = action,
793
789
one_of_them = if candidates.len() == 1 {
794
790
"it"
795
791
} else {
@@ -809,50 +805,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
809
805
// Get the `hir::Param` to verify whether it already has any bounds.
810
806
// We do this to avoid suggesting code that ends up as `T: FooBar`,
811
807
// instead we suggest `T: Foo + Bar` in that case.
812
- let mut has_bounds = None;
813
- let mut impl_trait = false;
814
- if let Node::GenericParam(ref param) = hir.get(id) {
815
- let kind = ¶m.kind;
816
- if let hir::GenericParamKind::Type { synthetic: Some(_), .. } = kind {
817
- // We've found `fn foo(x: impl Trait)` instead of
818
- // `fn foo<T>(x: T)`. We want to suggest the correct
819
- // `fn foo(x: impl Trait + TraitBound)` instead of
820
- // `fn foo<T: TraitBound>(x: T)`. (See #63706.)
821
- impl_trait = true;
822
- has_bounds = param.bounds.get(1);
823
- } else {
824
- has_bounds = param.bounds.get(0);
808
+ match hir.get(id) {
809
+ Node::GenericParam(ref param) => {
810
+ let mut impl_trait = false;
811
+ let has_bounds = if let hir::GenericParamKind::Type {
812
+ synthetic: Some(_), ..
813
+ } = ¶m.kind {
814
+ // We've found `fn foo(x: impl Trait)` instead of
815
+ // `fn foo<T>(x: T)`. We want to suggest the correct
816
+ // `fn foo(x: impl Trait + TraitBound)` instead of
817
+ // `fn foo<T: TraitBound>(x: T)`. (#63706)
818
+ impl_trait = true;
819
+ param.bounds.get(1)
820
+ } else {
821
+ param.bounds.get(0)
822
+ };
823
+ let sp = hir.span(id);
824
+ let sp = if let Some(first_bound) = has_bounds {
825
+ // `sp` only covers `T`, change it so that it covers
826
+ // `T:` when appropriate
827
+ sp.until(first_bound.span())
828
+ } else {
829
+ sp
830
+ };
831
+ // FIXME: contrast `t.def_id` against `param.bounds` to not suggest
832
+ // traits already there. That can happen when the cause is that
833
+ // we're in a const scope or associated function used as a method.
834
+ err.span_suggestions(
835
+ sp,
836
+ &message(format!(
837
+ "restrict type parameter `{}` with",
838
+ param.name.ident().as_str(),
839
+ )),
840
+ candidates.iter().map(|t| format!(
841
+ "{}{} {}{}",
842
+ param.name.ident().as_str(),
843
+ if impl_trait { " +" } else { ":" },
844
+ self.tcx.def_path_str(t.def_id),
845
+ if has_bounds.is_some() { " + "} else { "" },
846
+ )),
847
+ Applicability::MaybeIncorrect,
848
+ );
849
+ suggested = true;
850
+ }
851
+ Node::Item(hir::Item {
852
+ kind: hir::ItemKind::Trait(.., bounds, _), ident, ..
853
+ }) => {
854
+ let (sp, sep, article) = if bounds.is_empty() {
855
+ (ident.span.shrink_to_hi(), ":", "a")
856
+ } else {
857
+ (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
858
+ };
859
+ err.span_suggestions(
860
+ sp,
861
+ &message(format!("add {} supertrait for", article)),
862
+ candidates.iter().map(|t| format!(
863
+ "{} {}",
864
+ sep,
865
+ self.tcx.def_path_str(t.def_id),
866
+ )),
867
+ Applicability::MaybeIncorrect,
868
+ );
869
+ suggested = true;
825
870
}
871
+ _ => {}
826
872
}
827
- let sp = hir.span(id);
828
- // `sp` only covers `T`, change it so that it covers `T:` when appropriate.
829
- let sp = if let Some(first_bound) = has_bounds {
830
- sp.until(first_bound.span())
831
- } else {
832
- sp
833
- };
834
-
835
- // FIXME: contrast `t.def_id` against `param.bounds` to not suggest traits
836
- // already there. That can happen when the cause is that we're in a const
837
- // scope or associated function used as a method.
838
- err.span_suggestions(
839
- sp,
840
- &msg[..],
841
- candidates.iter().map(|t| format!(
842
- "{}{} {}{}",
843
- param,
844
- if impl_trait { " +" } else { ":" },
845
- self.tcx.def_path_str(t.def_id),
846
- if has_bounds.is_some() { " + " } else { "" },
847
- )),
848
- Applicability::MaybeIncorrect,
849
- );
850
- suggested = true;
851
873
}
852
874
};
853
875
}
854
876
855
877
if !suggested {
878
+ let mut msg = message(if let Some(param) = param_type {
879
+ format!("restrict type parameter `{}` with", param)
880
+ } else {
881
+ "implement".to_string()
882
+ });
856
883
for (i, trait_info) in candidates.iter().enumerate() {
857
884
msg.push_str(&format!(
858
885
"\ncandidate #{}: `{}`",
0 commit comments