Skip to content

Commit

Permalink
make compare_generic_param_kinds errors consistent
Browse files Browse the repository at this point in the history
  • Loading branch information
BoxyUwU committed May 5, 2022
1 parent 4208c53 commit fea1d76
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 166 deletions.
166 changes: 48 additions & 118 deletions compiler/rustc_typeck/src/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ use rustc_hir::intravisit;
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::ty;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::util::ExplicitSelf;
use rustc_middle::ty::{self, DefIdTree};
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
Expand Down Expand Up @@ -48,7 +48,7 @@ crate fn compare_impl_method<'tcx>(
return;
}

if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, trait_item_span) {
if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m) {
return;
}

Expand Down Expand Up @@ -973,7 +973,6 @@ fn compare_generic_param_kinds<'tcx>(
tcx: TyCtxt<'tcx>,
impl_item: &ty::AssocItem,
trait_item: &ty::AssocItem,
trait_item_span: Option<Span>,
) -> Result<(), ErrorGuaranteed> {
assert_eq!(impl_item.kind, trait_item.kind);

Expand All @@ -986,123 +985,54 @@ fn compare_generic_param_kinds<'tcx>(
})
};

let get_param_span = |param: &ty::GenericParamDef| match tcx.hir().get_if_local(param.def_id) {
Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span),
_ => None,
};
for (param_impl, param_trait) in
iter::zip(ty_const_params_of(impl_item.def_id), ty_const_params_of(trait_item.def_id))
{
use GenericParamDefKind::*;
if match (&param_impl.kind, &param_trait.kind) {
(Const { .. }, Const { .. })
if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) =>
{
true
}
(Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true,
// this is exhaustive so that anyone adding new generic param kinds knows
// to make sure this error is reported for them.
(Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false,
(Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(),
} {
let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind {
Const { .. } => {
format!("{} const parameter with type `{}`", prefix, tcx.type_of(param.def_id))
}
Type { .. } => format!("{} type parameter", prefix),
Lifetime { .. } => unreachable!(),
};

let get_param_ident = |param: &ty::GenericParamDef| match tcx.hir().get_if_local(param.def_id) {
Some(hir::Node::GenericParam(hir::GenericParam { name, .. })) => match name {
hir::ParamName::Plain(ident) => Some(ident),
_ => None,
},
other => bug!(
"expected GenericParam, found {:?}",
other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n))
),
};
let param_impl_span = tcx.def_span(param_impl.def_id);
let param_trait_span = tcx.def_span(param_trait.def_id);

let ty_const_params_impl = ty_const_params_of(impl_item.def_id);
let ty_const_params_trait = ty_const_params_of(trait_item.def_id);
let assoc_item_str = assoc_item_kind_str(&impl_item);
let mut err = struct_span_err!(
tcx.sess,
param_impl_span,
E0053,
"{} `{}` has an incompatible generic parameter for trait: `{}`",
assoc_item_kind_str(&impl_item),
trait_item.name,
&tcx.def_path_str(tcx.parent(trait_item.def_id))
);

for (param_impl, param_trait) in iter::zip(ty_const_params_impl, ty_const_params_trait) {
use GenericParamDefKind::*;
match (&param_impl.kind, &param_trait.kind) {
(Const { .. }, Const { .. }) => {
let impl_ty = tcx.type_of(param_impl.def_id);
let trait_ty = tcx.type_of(param_trait.def_id);
if impl_ty != trait_ty {
let param_impl_span = get_param_span(param_impl).unwrap();
let param_impl_ident = get_param_ident(param_impl);
let param_trait_span = get_param_span(param_trait);

let mut err = struct_span_err!(
tcx.sess,
*param_impl_span,
E0053,
"{} `{}` has an incompatible const parameter type for trait",
assoc_item_str,
trait_item.name,
);
err.span_note(
param_trait_span.map_or_else(
|| trait_item_span.unwrap_or(*param_impl_span),
|span| *span,
),
&format!(
"the const parameter{} has type `{}`, but the declaration \
in trait `{}` has type `{}`",
&param_impl_ident
.map_or_else(|| "".to_string(), |ident| format!(" `{ident}`")),
impl_ty,
tcx.def_path_str(trait_item.def_id),
trait_ty
),
);
let reported = err.emit();
return Err(reported);
}
}
(Const { .. }, Type { .. }) => {
let impl_ty = tcx.type_of(param_impl.def_id);
let param_impl_span = get_param_span(param_impl).unwrap();
let param_impl_ident = get_param_ident(param_impl);
let param_trait_span = get_param_span(param_trait);

let mut err = struct_span_err!(
tcx.sess,
*param_impl_span,
E0053,
"{} `{}` has an incompatible generic parameter for trait",
assoc_item_str,
trait_item.name,
);
err.span_note(
param_trait_span
.map_or_else(|| trait_item_span.unwrap_or(*param_impl_span), |span| *span),
&format!(
"the trait impl specifies{} a const parameter of type `{}`, but the declaration \
in trait `{}` requires it is a type parameter",
&param_impl_ident
.map_or_else(|| "".to_string(), |ident| format!(" `{ident}` is")),
impl_ty,
tcx.def_path_str(trait_item.def_id),
),
);
let reported = err.emit();
return Err(reported);
}
(Type { .. }, Const { .. }) => {
let trait_ty = tcx.type_of(param_trait.def_id);
let param_impl_span = get_param_span(param_impl).unwrap();
let param_impl_ident = get_param_ident(param_impl);
let param_trait_span = get_param_span(param_trait);

let mut err = struct_span_err!(
tcx.sess,
*param_impl_span,
E0053,
"{} `{}` has an incompatible generic parameter for trait",
assoc_item_str,
trait_item.name,
);
err.span_note(
param_trait_span
.map_or_else(|| trait_item_span.unwrap_or(*param_impl_span), |span| *span),
&format!(
"the trait impl specifies{} a type parameter, but the declaration \
in trait `{}` requires it is a const parameter of type `{}`",
&param_impl_ident
.map_or_else(|| "".to_string(), |ident| format!(" `{ident}` is")),
tcx.def_path_str(trait_item.def_id),
trait_ty,
),
);
let reported = err.emit();
return Err(reported);
}
_ => (),
let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap();
err.span_label(trait_header_span, "");
err.span_label(param_trait_span, make_param_message("expected", param_trait));

let impl_header_span =
tcx.sess.source_map().guess_head_span(tcx.def_span(tcx.parent(impl_item.def_id)));
err.span_label(impl_header_span, "");
err.span_label(param_impl_span, make_param_message("found", param_impl));

let reported = err.emit();
return Err(reported);
}
}

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

compare_generic_param_kinds(tcx, impl_ty, trait_ty, trait_item_span)?;
compare_generic_param_kinds(tcx, impl_ty, trait_ty)?;

let sp = tcx.def_span(impl_ty.def_id);
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,23 @@ trait Uwu {
}
impl Uwu for () {
fn baz<const N: i32>() {}
//~^ error: method `baz` has an incompatible const parameter type for trait
//~^ error: method `baz` has an incompatible generic parameter for trait
}

trait Aaaaaa {
fn bbbb<const N: u32, T>() {}
}
impl Aaaaaa for () {
fn bbbb<T, const N: u32>() {}
//~^ error: method `bbbb` has an incompatible generic parameter for trait
}

trait Names {
fn abcd<T, const N: u32>() {}
}
impl Names for () {
fn abcd<const N: u32, T>() {}
//~^ error: method `abcd` has an incompatible generic parameter for trait
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,39 +1,68 @@
error[E0053]: method `foo` has an incompatible generic parameter for trait
error[E0053]: method `foo` has an incompatible generic parameter for trait: `Trait`
--> $DIR/mismatched_ty_const_in_trait_impl.rs:5:12
|
LL | fn foo<const M: u64>() {}
| ^^^^^^^^^^^^
|
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
--> $DIR/mismatched_ty_const_in_trait_impl.rs:2:12
|
LL | trait Trait {
| -----
LL | fn foo<U>() {}
| ^
| - expected type parameter
LL | }
LL | impl Trait for () {
| -----------------
LL | fn foo<const M: u64>() {}
| ^^^^^^^^^^^^ found const parameter with type `u64`

error[E0053]: method `bar` has an incompatible generic parameter for trait
error[E0053]: method `bar` has an incompatible generic parameter for trait: `Other`
--> $DIR/mismatched_ty_const_in_trait_impl.rs:13:12
|
LL | fn bar<T>() {}
| ^
|
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`
--> $DIR/mismatched_ty_const_in_trait_impl.rs:10:12
|
LL | trait Other {
| -----
LL | fn bar<const M: u8>() {}
| ^^^^^^^^^^^
| ----------- expected const parameter with type `u8`
LL | }
LL | impl Other for () {
| -----------------
LL | fn bar<T>() {}
| ^ found type parameter

error[E0053]: method `baz` has an incompatible const parameter type for trait
error[E0053]: method `baz` has an incompatible generic parameter for trait: `Uwu`
--> $DIR/mismatched_ty_const_in_trait_impl.rs:21:12
|
LL | trait Uwu {
| ---
LL | fn baz<const N: u32>() {}
| ------------ expected const parameter with type `u32`
LL | }
LL | impl Uwu for () {
| ---------------
LL | fn baz<const N: i32>() {}
| ^^^^^^^^^^^^
| ^^^^^^^^^^^^ found const parameter with type `i32`

error[E0053]: method `bbbb` has an incompatible generic parameter for trait: `Aaaaaa`
--> $DIR/mismatched_ty_const_in_trait_impl.rs:29:13
|
note: the const parameter `N` has type `i32`, but the declaration in trait `Uwu::baz` has type `u32`
--> $DIR/mismatched_ty_const_in_trait_impl.rs:18:12
LL | trait Aaaaaa {
| ------
LL | fn bbbb<const N: u32, T>() {}
| ------------ expected const parameter with type `u32`
LL | }
LL | impl Aaaaaa for () {
| ------------------
LL | fn bbbb<T, const N: u32>() {}
| ^ found type parameter

error[E0053]: method `abcd` has an incompatible generic parameter for trait: `Names`
--> $DIR/mismatched_ty_const_in_trait_impl.rs:37:13
|
LL | fn baz<const N: u32>() {}
| ^^^^^^^^^^^^
LL | trait Names {
| -----
LL | fn abcd<T, const N: u32>() {}
| - expected type parameter
LL | }
LL | impl Names for () {
| -----------------
LL | fn abcd<const N: u32, T>() {}
| ^^^^^^^^^^^^ found const parameter with type `u32`

error: aborting due to 3 previous errors
error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0053`.
9 changes: 4 additions & 5 deletions src/test/ui/const-generics/issues/issue-86820.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Regression test for the ICE described in #86820.

#![allow(unused,dead_code)]
#![allow(unused, dead_code)]
use std::ops::BitAnd;

const C: fn() = || is_set();
Expand All @@ -9,13 +9,12 @@ fn is_set() {
}

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

impl Bits for u8 {
fn bit<const I : usize>(self) -> bool {
//~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053]
fn bit<const I: usize>(self) -> bool {
//~^ ERROR: method `bit` has an incompatible generic parameter for trait: `Bits` [E0053]
let i = 1 << I;
let mask = u8::from(i);
mask & self == mask
Expand Down
21 changes: 11 additions & 10 deletions src/test/ui/const-generics/issues/issue-86820.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
error[E0053]: method `bit` has an incompatible const parameter type for trait
--> $DIR/issue-86820.rs:17:12
error[E0053]: method `bit` has an incompatible generic parameter for trait: `Bits`
--> $DIR/issue-86820.rs:16:12
|
LL | fn bit<const I : usize>(self) -> bool {
| ^^^^^^^^^^^^^^^
|
note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
--> $DIR/issue-86820.rs:12:12
|
LL | fn bit<const I : u8>(self) -> bool;
| ^^^^^^^^^^^^
LL | trait Bits {
| ----
LL | fn bit<const I: u8>(self) -> bool;
| ----------- expected const parameter with type `u8`
...
LL | impl Bits for u8 {
| ----------------
LL | fn bit<const I: usize>(self) -> bool {
| ^^^^^^^^^^^^^^ found const parameter with type `usize`

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ trait Trait {

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

fn main() {}
Loading

0 comments on commit fea1d76

Please sign in to comment.