about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlexander Zhang <alex@alexyzhang.dev>2023-06-22 16:37:52 -0700
committerAlexander Zhang <alex@alexyzhang.dev>2023-06-22 16:37:52 -0700
commit48167bd4bddec03d1969e2cc2c1155cb5667d6ad (patch)
tree06f51fc27999860622967985fde940b5dd46ddbd
parent04075b32021932e3e8f6ab55d519b3b3494b6ef9 (diff)
Avoid guessing unknown trait impl in suggestions
When a trait is used without specifying the implementation (e.g. calling
a non-member associated function without fully-qualified syntax) and
there are multiple implementations available, use a placeholder comment
for the implementation type in the suggestion instead of picking a
random implementation.

Example:

```
fn main() {
    let _ = Default::default();
}
```

Previous output:

```
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
 --> test.rs:2:13
  |
2 |     let _ = Default::default();
  |             ^^^^^^^^^^^^^^^^ cannot call associated function of trait
  |
help: use a fully-qualified path to a specific available implementation (273 found)
  |
2 |     let _ = <FileTimes as Default>::default();
  |             +++++++++++++        +
```

New output:

```
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
 --> test.rs:2:13
  |
2 |     let _ = Default::default();
  |             ^^^^^^^^^^^^^^^^ cannot call associated function of trait
  |
help: use a fully-qualified path to a specific available implementation (273 found)
  |
2 |     let _ = </* self type */ as Default>::default();
  |             +++++++++++++++++++        +
```
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs16
-rw-r--r--tests/ui/error-codes/E0283.stderr4
-rw-r--r--tests/ui/error-codes/E0790.stderr4
3 files changed, 14 insertions, 10 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 75a92af714b..67745f04641 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2382,17 +2382,21 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             && let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next()
                         {
                             let non_blanket_impl_count = trait_impls.non_blanket_impls().values().flatten().count();
-                            let message = if non_blanket_impl_count == 1 {
-                                "use the fully-qualified path to the only available implementation".to_string()
-                            } else {
+                            // If there is only one implementation of the trait, suggest using it.
+                            // Otherwise, use a placeholder comment for the implementation.
+                            let (message, impl_suggestion) = if non_blanket_impl_count == 1 {(
+                                "use the fully-qualified path to the only available implementation".to_string(),
+                                format!("<{} as ", self.tcx.type_of(impl_def_id).subst_identity())
+                            )} else {(
                                 format!(
                                     "use a fully-qualified path to a specific available implementation ({} found)",
                                     non_blanket_impl_count
-                                )
-                            };
+                                ),
+                                "</* self type */ as ".to_string()
+                            )};
                             let mut suggestions = vec![(
                                 path.span.shrink_to_lo(),
-                                format!("<{} as ", self.tcx.type_of(impl_def_id).subst_identity())
+                                impl_suggestion
                             )];
                             if let Some(generic_arg) = trait_path_segment.args {
                                 let between_span = trait_path_segment.ident.span.between(generic_arg.span_ext);
diff --git a/tests/ui/error-codes/E0283.stderr b/tests/ui/error-codes/E0283.stderr
index 90316c6e981..89e634a7064 100644
--- a/tests/ui/error-codes/E0283.stderr
+++ b/tests/ui/error-codes/E0283.stderr
@@ -9,8 +9,8 @@ LL |     let cont: u32 = Generator::create();
    |
 help: use a fully-qualified path to a specific available implementation (2 found)
    |
-LL |     let cont: u32 = <Impl as Generator>::create();
-   |                     ++++++++          +
+LL |     let cont: u32 = </* self type */ as Generator>::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 fc025a3fca2..7248766285d 100644
--- a/tests/ui/error-codes/E0790.stderr
+++ b/tests/ui/error-codes/E0790.stderr
@@ -65,8 +65,8 @@ LL |     MyTrait2::my_fn();
    |
 help: use a fully-qualified path to a specific available implementation (2 found)
    |
-LL |     <Impl1 as MyTrait2>::my_fn();
-   |     +++++++++         +
+LL |     </* self type */ as MyTrait2>::my_fn();
+   |     +++++++++++++++++++         +
 
 error: aborting due to 5 previous errors