Skip to content

Commit

Permalink
Auto merge of #121416 - veera-sivarajan:bugfix-120785, r=nnethercote
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Feb 23, 2024
2 parents 8f359be + 3927057 commit 9203e70
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 4 deletions.
21 changes: 17 additions & 4 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1255,10 +1255,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 = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
let path1 = self.tcx.def_path_str(did1);
let path2 = self.tcx.def_path_str(did2);
Expand Down
24 changes: 24 additions & 0 deletions compiler/rustc_middle/src/ty/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 9203e70

Please sign in to comment.