about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-08-02 02:39:37 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-08-02 03:22:56 +0000
commit2c83c99058e8b2ae12013469b6c4fde27b648874 (patch)
treeec06a75b995fd4e4676074e91273dffc001d5fb4
parente60ebb2f2c1facba87e7971798f3cbdfd309cd23 (diff)
downloadrust-2c83c99058e8b2ae12013469b6c4fde27b648874.tar.gz
rust-2c83c99058e8b2ae12013469b6c4fde27b648874.zip
More information for fully-qualified suggestion when there are multiple impls
```
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
  --> $DIR/E0283.rs:30:21
   |
LL |     fn create() -> u32;
   |     ------------------- `Coroutine::create` defined here
...
LL |     let cont: u32 = Coroutine::create();
   |                     ^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
   |
help: use a fully-qualified path to a specific available implementation
   |
LL |     let cont: u32 = <Impl as Coroutine>::create();
   |                     ++++++++          +
LL |     let cont: u32 = <AnotherImpl as Coroutine>::create();
   |                     +++++++++++++++          +
```
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs70
-rw-r--r--tests/ui/error-codes/E0283.stderr8
-rw-r--r--tests/ui/error-codes/E0790.stderr8
3 files changed, 59 insertions, 27 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index 72a4d4c1205..9ab47057859 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -388,39 +388,67 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                 trait_impls.non_blanket_impls().values().flatten().count();
                             // If there is only one implementation of the trait, suggest using it.
                             // Otherwise, use a placeholder comment for the implementation.
-                            let (message, self_type) = if non_blanket_impl_count == 1 {
+                            let (message, self_types) = if non_blanket_impl_count == 1 {
                                 (
                                     "use the fully-qualified path to the only available \
                                      implementation",
-                                    format!(
+                                    vec![format!(
                                         "{}",
                                         self.tcx.type_of(impl_def_id).instantiate_identity()
-                                    ),
+                                    )],
+                                )
+                            } else if non_blanket_impl_count < 20 {
+                                (
+                                    "use a fully-qualified path to one of the available \
+                                     implementations",
+                                    trait_impls
+                                        .non_blanket_impls()
+                                        .values()
+                                        .flatten()
+                                        .map(|id| {
+                                            format!(
+                                                "{}",
+                                                self.tcx.type_of(id).instantiate_identity()
+                                            )
+                                        })
+                                        .collect::<Vec<String>>(),
                                 )
                             } else {
                                 (
                                     "use a fully-qualified path to a specific available \
                                      implementation",
-                                    "/* self type */".to_string(),
+                                    vec!["/* self type */".to_string()],
                                 )
                             };
-                            let mut suggestions =
-                                vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))];
-                            if let Some(generic_arg) = trait_path_segment.args {
-                                let between_span =
-                                    trait_path_segment.ident.span.between(generic_arg.span_ext);
-                                // get rid of :: between Trait and <type>
-                                // must be '::' between them, otherwise the parser won't accept the code
-                                suggestions.push((between_span, "".to_string()));
-                                suggestions
-                                    .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
-                            } else {
-                                suggestions.push((
-                                    trait_path_segment.ident.span.shrink_to_hi(),
-                                    ">".to_string(),
-                                ));
-                            }
-                            err.multipart_suggestion(
+                            let suggestions: Vec<_> = self_types
+                                .into_iter()
+                                .map(|self_type| {
+                                    let mut suggestions = vec![(
+                                        path.span.shrink_to_lo(),
+                                        format!("<{self_type} as "),
+                                    )];
+                                    if let Some(generic_arg) = trait_path_segment.args {
+                                        let between_span = trait_path_segment
+                                            .ident
+                                            .span
+                                            .between(generic_arg.span_ext);
+                                        // get rid of :: between Trait and <type>
+                                        // must be '::' between them, otherwise the parser won't accept the code
+                                        suggestions.push((between_span, "".to_string()));
+                                        suggestions.push((
+                                            generic_arg.span_ext.shrink_to_hi(),
+                                            ">".to_string(),
+                                        ));
+                                    } else {
+                                        suggestions.push((
+                                            trait_path_segment.ident.span.shrink_to_hi(),
+                                            ">".to_string(),
+                                        ));
+                                    }
+                                    suggestions
+                                })
+                                .collect();
+                            err.multipart_suggestions(
                                 message,
                                 suggestions,
                                 Applicability::MaybeIncorrect,
diff --git a/tests/ui/error-codes/E0283.stderr b/tests/ui/error-codes/E0283.stderr
index fc08395a2b0..381eca5f2a4 100644
--- a/tests/ui/error-codes/E0283.stderr
+++ b/tests/ui/error-codes/E0283.stderr
@@ -7,10 +7,12 @@ LL |     fn create() -> u32;
 LL |     let cont: u32 = Coroutine::create();
    |                     ^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
    |
-help: use a fully-qualified path to a specific available implementation
+help: use a fully-qualified path to one of the available implementations
    |
-LL |     let cont: u32 = </* self type */ as Coroutine>::create();
-   |                     +++++++++++++++++++          +
+LL |     let cont: u32 = <Impl as Coroutine>::create();
+   |                     ++++++++          +
+LL |     let cont: u32 = <AnotherImpl as Coroutine>::create();
+   |                     +++++++++++++++          +
 
 error[E0283]: type annotations needed
   --> $DIR/E0283.rs:35:24
diff --git a/tests/ui/error-codes/E0790.stderr b/tests/ui/error-codes/E0790.stderr
index 6338a10b6af..106554b2425 100644
--- a/tests/ui/error-codes/E0790.stderr
+++ b/tests/ui/error-codes/E0790.stderr
@@ -63,10 +63,12 @@ LL |     fn my_fn();
 LL |     MyTrait2::my_fn();
    |     ^^^^^^^^^^^^^^^^^ cannot call associated function of trait
    |
-help: use a fully-qualified path to a specific available implementation
+help: use a fully-qualified path to one of the available implementations
    |
-LL |     </* self type */ as MyTrait2>::my_fn();
-   |     +++++++++++++++++++         +
+LL |     <Impl1 as MyTrait2>::my_fn();
+   |     +++++++++         +
+LL |     <Impl2 as MyTrait2>::my_fn();
+   |     +++++++++         +
 
 error: aborting due to 5 previous errors