about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-03-01 17:51:28 +0100
committerGitHub <noreply@github.com>2024-03-01 17:51:28 +0100
commitf23c6ddada3924caa6face1f851e70da20859f48 (patch)
treed825215041128b36e174e5fa27586e91c8afbebf
parent80549a881137dfc78b6b2c705440ff5221456d63 (diff)
parentcc13f8278f22243a6ecd82d062c4740787a0fc51 (diff)
downloadrust-f23c6ddada3924caa6face1f851e70da20859f48.tar.gz
rust-f23c6ddada3924caa6face1f851e70da20859f48.zip
Rollup merge of #121416 - veera-sivarajan:bugfix-120785, r=nnethercote
Improve error messages for generics with default parameters

Fixes #120785

Issue: Previously, all type parameters with default types were deliberately ignored to simplify error messages. For example, an error message for Box type would display `Box<T>` instead of `Box<T, _>`. But, this resulted in unclear error message when a concrete type was used instead of the default type.

Fix: This PR fixes it by checking if a concrete type is specified after a default type to display the entire type name or the simplified type name.
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs21
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs24
-rw-r--r--tests/ui/type/clarify-error-for-generics-with-default-issue-120785.rs11
-rw-r--r--tests/ui/type/clarify-error-for-generics-with-default-issue-120785.stderr27
4 files changed, 79 insertions, 4 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 1cf990fef04..af1aa346c09 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1247,10 +1247,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => {
                 let did1 = def1.did();
                 let did2 = def2.did();
-                let sub_no_defaults_1 =
-                    self.tcx.generics_of(did1).own_args_no_defaults(self.tcx, sub1);
-                let sub_no_defaults_2 =
-                    self.tcx.generics_of(did2).own_args_no_defaults(self.tcx, sub2);
+
+                let generics1 = self.tcx.generics_of(did1);
+                let generics2 = self.tcx.generics_of(did2);
+
+                let non_default_after_default = generics1
+                    .check_concrete_type_after_default(self.tcx, sub1)
+                    || generics2.check_concrete_type_after_default(self.tcx, sub2);
+                let sub_no_defaults_1 = if non_default_after_default {
+                    generics1.own_args(sub1)
+                } else {
+                    generics1.own_args_no_defaults(self.tcx, sub1)
+                };
+                let sub_no_defaults_2 = if non_default_after_default {
+                    generics2.own_args(sub2)
+                } else {
+                    generics2.own_args_no_defaults(self.tcx, sub2)
+                };
                 let mut values = (DiagStyledString::new(), DiagStyledString::new());
                 let path1 = self.tcx.def_path_str(did1);
                 let path2 = self.tcx.def_path_str(did2);
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index c81d9dfbc7d..2630b96869b 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -360,6 +360,30 @@ impl<'tcx> Generics {
         let own = &args[self.parent_count..][..self.params.len()];
         if self.has_self && self.parent.is_none() { &own[1..] } else { own }
     }
+
+    /// Returns true if a concrete type is specified after a default type.
+    /// For example, consider `struct T<W = usize, X = Vec<W>>(W, X)`
+    /// `T<usize, String>` will return true
+    /// `T<usize>` will return false
+    pub fn check_concrete_type_after_default(
+        &'tcx self,
+        tcx: TyCtxt<'tcx>,
+        args: &'tcx [ty::GenericArg<'tcx>],
+    ) -> bool {
+        let mut default_param_seen = false;
+        for param in self.params.iter() {
+            if let Some(inst) =
+                param.default_value(tcx).map(|default| default.instantiate(tcx, args))
+            {
+                if inst == args[param.index as usize] {
+                    default_param_seen = true;
+                } else if default_param_seen {
+                    return true;
+                }
+            }
+        }
+        false
+    }
 }
 
 /// Bounds on generics.
diff --git a/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.rs b/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.rs
new file mode 100644
index 00000000000..7a923179d3b
--- /dev/null
+++ b/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.rs
@@ -0,0 +1,11 @@
+struct What<W = usize, X = Vec<W>>(W, X);
+
+fn main() {
+    let mut b: What<usize> = What(5, vec![1, 2, 3]);
+    let c: What<usize, String> = What(1, String::from("meow"));
+    b = c; //~ ERROR mismatched types
+
+    let mut f: What<usize, Vec<String>> = What(1, vec![String::from("meow")]);
+    let e: What<usize> = What(5, vec![1, 2, 3]);
+    f = e; //~ ERROR mismatched types
+}
diff --git a/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.stderr b/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.stderr
new file mode 100644
index 00000000000..d2b3397fbcb
--- /dev/null
+++ b/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.stderr
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+  --> $DIR/clarify-error-for-generics-with-default-issue-120785.rs:6:9
+   |
+LL |     let mut b: What<usize> = What(5, vec![1, 2, 3]);
+   |                ----------- expected due to this type
+LL |     let c: What<usize, String> = What(1, String::from("meow"));
+LL |     b = c;
+   |         ^ expected `What`, found `What<usize, String>`
+   |
+   = note: expected struct `What<_, Vec<usize>>`
+              found struct `What<_, String>`
+
+error[E0308]: mismatched types
+  --> $DIR/clarify-error-for-generics-with-default-issue-120785.rs:10:9
+   |
+LL |     let mut f: What<usize, Vec<String>> = What(1, vec![String::from("meow")]);
+   |                ------------------------ expected due to this type
+LL |     let e: What<usize> = What(5, vec![1, 2, 3]);
+LL |     f = e;
+   |         ^ expected `What<usize, Vec<String>>`, found `What`
+   |
+   = note: expected struct `What<_, Vec<String>>`
+              found struct `What<_, Vec<usize>>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.