about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVeera <sveera.2001@gmail.com>2024-02-21 16:46:57 -0500
committerVeera <sveera.2001@gmail.com>2024-02-28 19:28:18 -0500
commit49961947c8a830fc1d5d4ecc5916267a7e4bb6b0 (patch)
treebfccc5fc853a69893f4fdd9638da95dcd381b7b5
parentc475e2303b551d726307c646181e0677af1e0069 (diff)
downloadrust-49961947c8a830fc1d5d4ecc5916267a7e4bb6b0.tar.gz
rust-49961947c8a830fc1d5d4ecc5916267a7e4bb6b0.zip
Improve error messages for generics with default parameters
Fixes #120785
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs21
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs27
-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, 82 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 911b2f16c8b..38214ab72e6 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..4f75b7b42fb 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -360,6 +360,33 @@ 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 param
+                .default_value(tcx)
+                .is_some_and(|default| default.instantiate(tcx, args) == args[param.index as usize])
+            {
+                default_param_seen = true;
+            } else if default_param_seen
+                && param.default_value(tcx).is_some_and(|default| {
+                    default.instantiate(tcx, args) != args[param.index as usize]
+                })
+            {
+                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..a39c0049d01
--- /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 e: What<usize> = What(5, vec![1, 2, 3]);
+    let f: What<usize, Vec<String>> = What(1, vec![String::from("meow")]);
+    e = f; //~ 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..60fd18b968c
--- /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 e: What<usize> = What(5, vec![1, 2, 3]);
+   |                ----------- expected due to this type
+LL |     let f: What<usize, Vec<String>> = What(1, vec![String::from("meow")]);
+LL |     e = f;
+   |         ^ expected `What`, found `What<usize, Vec<String>>`
+   |
+   = note: expected struct `What<_, Vec<usize>>`
+              found struct `What<_, Vec<String>>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.