diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2024-08-02 02:39:37 +0000 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2024-08-02 03:22:56 +0000 |
| commit | 2c83c99058e8b2ae12013469b6c4fde27b648874 (patch) | |
| tree | ec06a75b995fd4e4676074e91273dffc001d5fb4 | |
| parent | e60ebb2f2c1facba87e7971798f3cbdfd309cd23 (diff) | |
| download | rust-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.rs | 70 | ||||
| -rw-r--r-- | tests/ui/error-codes/E0283.stderr | 8 | ||||
| -rw-r--r-- | tests/ui/error-codes/E0790.stderr | 8 |
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 |
