Skip to content

Commit fea1d76

Browse files
committed
make compare_generic_param_kinds errors consistent
1 parent 4208c53 commit fea1d76

File tree

7 files changed

+142
-166
lines changed

7 files changed

+142
-166
lines changed

compiler/rustc_typeck/src/check/compare_method.rs

Lines changed: 48 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ use rustc_hir::intravisit;
77
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
88
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
99
use rustc_infer::traits::util;
10-
use rustc_middle::ty;
1110
use rustc_middle::ty::error::{ExpectedFound, TypeError};
1211
use rustc_middle::ty::subst::{InternalSubsts, Subst};
1312
use rustc_middle::ty::util::ExplicitSelf;
13+
use rustc_middle::ty::{self, DefIdTree};
1414
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
1515
use rustc_span::Span;
1616
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
@@ -48,7 +48,7 @@ crate fn compare_impl_method<'tcx>(
4848
return;
4949
}
5050

51-
if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, trait_item_span) {
51+
if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m) {
5252
return;
5353
}
5454

@@ -973,7 +973,6 @@ fn compare_generic_param_kinds<'tcx>(
973973
tcx: TyCtxt<'tcx>,
974974
impl_item: &ty::AssocItem,
975975
trait_item: &ty::AssocItem,
976-
trait_item_span: Option<Span>,
977976
) -> Result<(), ErrorGuaranteed> {
978977
assert_eq!(impl_item.kind, trait_item.kind);
979978

@@ -986,123 +985,54 @@ fn compare_generic_param_kinds<'tcx>(
986985
})
987986
};
988987

989-
let get_param_span = |param: &ty::GenericParamDef| match tcx.hir().get_if_local(param.def_id) {
990-
Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span),
991-
_ => None,
992-
};
988+
for (param_impl, param_trait) in
989+
iter::zip(ty_const_params_of(impl_item.def_id), ty_const_params_of(trait_item.def_id))
990+
{
991+
use GenericParamDefKind::*;
992+
if match (&param_impl.kind, &param_trait.kind) {
993+
(Const { .. }, Const { .. })
994+
if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) =>
995+
{
996+
true
997+
}
998+
(Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true,
999+
// this is exhaustive so that anyone adding new generic param kinds knows
1000+
// to make sure this error is reported for them.
1001+
(Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false,
1002+
(Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(),
1003+
} {
1004+
let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind {
1005+
Const { .. } => {
1006+
format!("{} const parameter with type `{}`", prefix, tcx.type_of(param.def_id))
1007+
}
1008+
Type { .. } => format!("{} type parameter", prefix),
1009+
Lifetime { .. } => unreachable!(),
1010+
};
9931011

994-
let get_param_ident = |param: &ty::GenericParamDef| match tcx.hir().get_if_local(param.def_id) {
995-
Some(hir::Node::GenericParam(hir::GenericParam { name, .. })) => match name {
996-
hir::ParamName::Plain(ident) => Some(ident),
997-
_ => None,
998-
},
999-
other => bug!(
1000-
"expected GenericParam, found {:?}",
1001-
other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n))
1002-
),
1003-
};
1012+
let param_impl_span = tcx.def_span(param_impl.def_id);
1013+
let param_trait_span = tcx.def_span(param_trait.def_id);
10041014

1005-
let ty_const_params_impl = ty_const_params_of(impl_item.def_id);
1006-
let ty_const_params_trait = ty_const_params_of(trait_item.def_id);
1007-
let assoc_item_str = assoc_item_kind_str(&impl_item);
1015+
let mut err = struct_span_err!(
1016+
tcx.sess,
1017+
param_impl_span,
1018+
E0053,
1019+
"{} `{}` has an incompatible generic parameter for trait: `{}`",
1020+
assoc_item_kind_str(&impl_item),
1021+
trait_item.name,
1022+
&tcx.def_path_str(tcx.parent(trait_item.def_id))
1023+
);
10081024

1009-
for (param_impl, param_trait) in iter::zip(ty_const_params_impl, ty_const_params_trait) {
1010-
use GenericParamDefKind::*;
1011-
match (&param_impl.kind, &param_trait.kind) {
1012-
(Const { .. }, Const { .. }) => {
1013-
let impl_ty = tcx.type_of(param_impl.def_id);
1014-
let trait_ty = tcx.type_of(param_trait.def_id);
1015-
if impl_ty != trait_ty {
1016-
let param_impl_span = get_param_span(param_impl).unwrap();
1017-
let param_impl_ident = get_param_ident(param_impl);
1018-
let param_trait_span = get_param_span(param_trait);
1019-
1020-
let mut err = struct_span_err!(
1021-
tcx.sess,
1022-
*param_impl_span,
1023-
E0053,
1024-
"{} `{}` has an incompatible const parameter type for trait",
1025-
assoc_item_str,
1026-
trait_item.name,
1027-
);
1028-
err.span_note(
1029-
param_trait_span.map_or_else(
1030-
|| trait_item_span.unwrap_or(*param_impl_span),
1031-
|span| *span,
1032-
),
1033-
&format!(
1034-
"the const parameter{} has type `{}`, but the declaration \
1035-
in trait `{}` has type `{}`",
1036-
&param_impl_ident
1037-
.map_or_else(|| "".to_string(), |ident| format!(" `{ident}`")),
1038-
impl_ty,
1039-
tcx.def_path_str(trait_item.def_id),
1040-
trait_ty
1041-
),
1042-
);
1043-
let reported = err.emit();
1044-
return Err(reported);
1045-
}
1046-
}
1047-
(Const { .. }, Type { .. }) => {
1048-
let impl_ty = tcx.type_of(param_impl.def_id);
1049-
let param_impl_span = get_param_span(param_impl).unwrap();
1050-
let param_impl_ident = get_param_ident(param_impl);
1051-
let param_trait_span = get_param_span(param_trait);
1052-
1053-
let mut err = struct_span_err!(
1054-
tcx.sess,
1055-
*param_impl_span,
1056-
E0053,
1057-
"{} `{}` has an incompatible generic parameter for trait",
1058-
assoc_item_str,
1059-
trait_item.name,
1060-
);
1061-
err.span_note(
1062-
param_trait_span
1063-
.map_or_else(|| trait_item_span.unwrap_or(*param_impl_span), |span| *span),
1064-
&format!(
1065-
"the trait impl specifies{} a const parameter of type `{}`, but the declaration \
1066-
in trait `{}` requires it is a type parameter",
1067-
&param_impl_ident
1068-
.map_or_else(|| "".to_string(), |ident| format!(" `{ident}` is")),
1069-
impl_ty,
1070-
tcx.def_path_str(trait_item.def_id),
1071-
),
1072-
);
1073-
let reported = err.emit();
1074-
return Err(reported);
1075-
}
1076-
(Type { .. }, Const { .. }) => {
1077-
let trait_ty = tcx.type_of(param_trait.def_id);
1078-
let param_impl_span = get_param_span(param_impl).unwrap();
1079-
let param_impl_ident = get_param_ident(param_impl);
1080-
let param_trait_span = get_param_span(param_trait);
1081-
1082-
let mut err = struct_span_err!(
1083-
tcx.sess,
1084-
*param_impl_span,
1085-
E0053,
1086-
"{} `{}` has an incompatible generic parameter for trait",
1087-
assoc_item_str,
1088-
trait_item.name,
1089-
);
1090-
err.span_note(
1091-
param_trait_span
1092-
.map_or_else(|| trait_item_span.unwrap_or(*param_impl_span), |span| *span),
1093-
&format!(
1094-
"the trait impl specifies{} a type parameter, but the declaration \
1095-
in trait `{}` requires it is a const parameter of type `{}`",
1096-
&param_impl_ident
1097-
.map_or_else(|| "".to_string(), |ident| format!(" `{ident}` is")),
1098-
tcx.def_path_str(trait_item.def_id),
1099-
trait_ty,
1100-
),
1101-
);
1102-
let reported = err.emit();
1103-
return Err(reported);
1104-
}
1105-
_ => (),
1025+
let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap();
1026+
err.span_label(trait_header_span, "");
1027+
err.span_label(param_trait_span, make_param_message("expected", param_trait));
1028+
1029+
let impl_header_span =
1030+
tcx.sess.source_map().guess_head_span(tcx.def_span(tcx.parent(impl_item.def_id)));
1031+
err.span_label(impl_header_span, "");
1032+
err.span_label(param_impl_span, make_param_message("found", param_impl));
1033+
1034+
let reported = err.emit();
1035+
return Err(reported);
11061036
}
11071037
}
11081038

@@ -1228,7 +1158,7 @@ crate fn compare_ty_impl<'tcx>(
12281158
let _: Result<(), ErrorGuaranteed> = (|| {
12291159
compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
12301160

1231-
compare_generic_param_kinds(tcx, impl_ty, trait_ty, trait_item_span)?;
1161+
compare_generic_param_kinds(tcx, impl_ty, trait_ty)?;
12321162

12331163
let sp = tcx.def_span(impl_ty.def_id);
12341164
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;

src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,23 @@ trait Uwu {
1919
}
2020
impl Uwu for () {
2121
fn baz<const N: i32>() {}
22-
//~^ error: method `baz` has an incompatible const parameter type for trait
22+
//~^ error: method `baz` has an incompatible generic parameter for trait
23+
}
24+
25+
trait Aaaaaa {
26+
fn bbbb<const N: u32, T>() {}
27+
}
28+
impl Aaaaaa for () {
29+
fn bbbb<T, const N: u32>() {}
30+
//~^ error: method `bbbb` has an incompatible generic parameter for trait
31+
}
32+
33+
trait Names {
34+
fn abcd<T, const N: u32>() {}
35+
}
36+
impl Names for () {
37+
fn abcd<const N: u32, T>() {}
38+
//~^ error: method `abcd` has an incompatible generic parameter for trait
2339
}
2440

2541
fn main() {}
Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,68 @@
1-
error[E0053]: method `foo` has an incompatible generic parameter for trait
1+
error[E0053]: method `foo` has an incompatible generic parameter for trait: `Trait`
22
--> $DIR/mismatched_ty_const_in_trait_impl.rs:5:12
33
|
4-
LL | fn foo<const M: u64>() {}
5-
| ^^^^^^^^^^^^
6-
|
7-
note: the trait impl specifies `M` is a const parameter of type `u64`, but the declaration in trait `Trait::foo` requires it is a type parameter
8-
--> $DIR/mismatched_ty_const_in_trait_impl.rs:2:12
9-
|
4+
LL | trait Trait {
5+
| -----
106
LL | fn foo<U>() {}
11-
| ^
7+
| - expected type parameter
8+
LL | }
9+
LL | impl Trait for () {
10+
| -----------------
11+
LL | fn foo<const M: u64>() {}
12+
| ^^^^^^^^^^^^ found const parameter with type `u64`
1213

13-
error[E0053]: method `bar` has an incompatible generic parameter for trait
14+
error[E0053]: method `bar` has an incompatible generic parameter for trait: `Other`
1415
--> $DIR/mismatched_ty_const_in_trait_impl.rs:13:12
1516
|
16-
LL | fn bar<T>() {}
17-
| ^
18-
|
19-
note: the trait impl specifies `T` is a type parameter, but the declaration in trait `Other::bar` requires it is a const parameter of type `u8`
20-
--> $DIR/mismatched_ty_const_in_trait_impl.rs:10:12
21-
|
17+
LL | trait Other {
18+
| -----
2219
LL | fn bar<const M: u8>() {}
23-
| ^^^^^^^^^^^
20+
| ----------- expected const parameter with type `u8`
21+
LL | }
22+
LL | impl Other for () {
23+
| -----------------
24+
LL | fn bar<T>() {}
25+
| ^ found type parameter
2426

25-
error[E0053]: method `baz` has an incompatible const parameter type for trait
27+
error[E0053]: method `baz` has an incompatible generic parameter for trait: `Uwu`
2628
--> $DIR/mismatched_ty_const_in_trait_impl.rs:21:12
2729
|
30+
LL | trait Uwu {
31+
| ---
32+
LL | fn baz<const N: u32>() {}
33+
| ------------ expected const parameter with type `u32`
34+
LL | }
35+
LL | impl Uwu for () {
36+
| ---------------
2837
LL | fn baz<const N: i32>() {}
29-
| ^^^^^^^^^^^^
38+
| ^^^^^^^^^^^^ found const parameter with type `i32`
39+
40+
error[E0053]: method `bbbb` has an incompatible generic parameter for trait: `Aaaaaa`
41+
--> $DIR/mismatched_ty_const_in_trait_impl.rs:29:13
3042
|
31-
note: the const parameter `N` has type `i32`, but the declaration in trait `Uwu::baz` has type `u32`
32-
--> $DIR/mismatched_ty_const_in_trait_impl.rs:18:12
43+
LL | trait Aaaaaa {
44+
| ------
45+
LL | fn bbbb<const N: u32, T>() {}
46+
| ------------ expected const parameter with type `u32`
47+
LL | }
48+
LL | impl Aaaaaa for () {
49+
| ------------------
50+
LL | fn bbbb<T, const N: u32>() {}
51+
| ^ found type parameter
52+
53+
error[E0053]: method `abcd` has an incompatible generic parameter for trait: `Names`
54+
--> $DIR/mismatched_ty_const_in_trait_impl.rs:37:13
3355
|
34-
LL | fn baz<const N: u32>() {}
35-
| ^^^^^^^^^^^^
56+
LL | trait Names {
57+
| -----
58+
LL | fn abcd<T, const N: u32>() {}
59+
| - expected type parameter
60+
LL | }
61+
LL | impl Names for () {
62+
| -----------------
63+
LL | fn abcd<const N: u32, T>() {}
64+
| ^^^^^^^^^^^^ found const parameter with type `u32`
3665

37-
error: aborting due to 3 previous errors
66+
error: aborting due to 5 previous errors
3867

3968
For more information about this error, try `rustc --explain E0053`.

src/test/ui/const-generics/issues/issue-86820.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Regression test for the ICE described in #86820.
22

3-
#![allow(unused,dead_code)]
3+
#![allow(unused, dead_code)]
44
use std::ops::BitAnd;
55

66
const C: fn() = || is_set();
@@ -9,13 +9,12 @@ fn is_set() {
99
}
1010

1111
trait Bits {
12-
fn bit<const I : u8>(self) -> bool;
13-
//~^ NOTE: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
12+
fn bit<const I: u8>(self) -> bool;
1413
}
1514

1615
impl Bits for u8 {
17-
fn bit<const I : usize>(self) -> bool {
18-
//~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053]
16+
fn bit<const I: usize>(self) -> bool {
17+
//~^ ERROR: method `bit` has an incompatible generic parameter for trait: `Bits` [E0053]
1918
let i = 1 << I;
2019
let mask = u8::from(i);
2120
mask & self == mask

src/test/ui/const-generics/issues/issue-86820.stderr

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
error[E0053]: method `bit` has an incompatible const parameter type for trait
2-
--> $DIR/issue-86820.rs:17:12
1+
error[E0053]: method `bit` has an incompatible generic parameter for trait: `Bits`
2+
--> $DIR/issue-86820.rs:16:12
33
|
4-
LL | fn bit<const I : usize>(self) -> bool {
5-
| ^^^^^^^^^^^^^^^
6-
|
7-
note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
8-
--> $DIR/issue-86820.rs:12:12
9-
|
10-
LL | fn bit<const I : u8>(self) -> bool;
11-
| ^^^^^^^^^^^^
4+
LL | trait Bits {
5+
| ----
6+
LL | fn bit<const I: u8>(self) -> bool;
7+
| ----------- expected const parameter with type `u8`
8+
...
9+
LL | impl Bits for u8 {
10+
| ----------------
11+
LL | fn bit<const I: usize>(self) -> bool {
12+
| ^^^^^^^^^^^^^^ found const parameter with type `usize`
1213

1314
error: aborting due to previous error
1415

src/test/ui/generic-associated-types/const_params_have_right_type.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ trait Trait {
66

77
impl Trait for () {
88
type Foo<const N: u64> = u32;
9-
//~^ error: type `Foo` has an incompatible const parameter type
9+
//~^ error: type `Foo` has an incompatible generic parameter for trait
1010
}
1111

1212
fn main() {}

0 commit comments

Comments
 (0)