handle mismatched generic parameter kinds
This commit is contained in:
parent
fed2c43bbf
commit
6225e980bf
@ -48,6 +48,10 @@ crate fn compare_impl_method<'tcx>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, trait_item_span) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(_) =
|
if let Err(_) =
|
||||||
compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
|
compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
|
||||||
{
|
{
|
||||||
@ -62,10 +66,6 @@ crate fn compare_impl_method<'tcx>(
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(_) = compare_const_param_types(tcx, impl_m, trait_m, trait_item_span) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compare_predicate_entailment<'tcx>(
|
fn compare_predicate_entailment<'tcx>(
|
||||||
@ -914,62 +914,165 @@ fn compare_synthetic_generics<'tcx>(
|
|||||||
if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
|
if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compare_const_param_types<'tcx>(
|
/// Checks that all parameters in the generics of a given assoc item in a trait impl have
|
||||||
|
/// the same kind as the respective generic parameter in the trait def.
|
||||||
|
///
|
||||||
|
/// For example all 4 errors in the following code are emitted here:
|
||||||
|
/// ```
|
||||||
|
/// trait Foo {
|
||||||
|
/// fn foo<const N: u8>();
|
||||||
|
/// type bar<const N: u8>;
|
||||||
|
/// fn baz<const N: u32>();
|
||||||
|
/// type blah<T>;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Foo for () {
|
||||||
|
/// fn foo<const N: u64>() {}
|
||||||
|
/// //~^ error
|
||||||
|
/// type bar<const N: u64> {}
|
||||||
|
/// //~^ error
|
||||||
|
/// fn baz<T>() {}
|
||||||
|
/// //~^ error
|
||||||
|
/// type blah<const N: i64> = u32;
|
||||||
|
/// //~^ error
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This function does not handle lifetime parameters
|
||||||
|
fn compare_generic_param_kinds<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impl_m: &ty::AssocItem,
|
impl_item: &ty::AssocItem,
|
||||||
trait_m: &ty::AssocItem,
|
trait_item: &ty::AssocItem,
|
||||||
trait_item_span: Option<Span>,
|
trait_item_span: Option<Span>,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let const_params_of = |def_id| {
|
assert_eq!(impl_item.kind, trait_item.kind);
|
||||||
tcx.generics_of(def_id).params.iter().filter_map(|param| match param.kind {
|
|
||||||
GenericParamDefKind::Const { .. } => Some(param.def_id),
|
let ty_const_params_of = |def_id| {
|
||||||
_ => None,
|
tcx.generics_of(def_id).params.iter().filter(|param| {
|
||||||
|
matches!(
|
||||||
|
param.kind,
|
||||||
|
GenericParamDefKind::Const { .. } | GenericParamDefKind::Type { .. }
|
||||||
|
)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
let const_params_impl = const_params_of(impl_m.def_id);
|
|
||||||
let const_params_trait = const_params_of(trait_m.def_id);
|
|
||||||
|
|
||||||
for (const_param_impl, const_param_trait) in iter::zip(const_params_impl, const_params_trait) {
|
let get_param_span = |param: &ty::GenericParamDef| match tcx.hir().get_if_local(param.def_id) {
|
||||||
let impl_ty = tcx.type_of(const_param_impl);
|
Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span),
|
||||||
let trait_ty = tcx.type_of(const_param_trait);
|
_ => None,
|
||||||
if impl_ty != trait_ty {
|
};
|
||||||
let (impl_span, impl_ident) = match tcx.hir().get_if_local(const_param_impl) {
|
|
||||||
Some(hir::Node::GenericParam(hir::GenericParam { span, name, .. })) => (
|
let get_param_ident = |param: &ty::GenericParamDef| match tcx.hir().get_if_local(param.def_id) {
|
||||||
span,
|
Some(hir::Node::GenericParam(hir::GenericParam { name, .. })) => match name {
|
||||||
match name {
|
hir::ParamName::Plain(ident) => Some(ident),
|
||||||
hir::ParamName::Plain(ident) => Some(ident),
|
_ => None,
|
||||||
_ => None,
|
},
|
||||||
},
|
other => bug!(
|
||||||
),
|
"expected GenericParam, found {:?}",
|
||||||
other => bug!(
|
other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n))
|
||||||
"expected GenericParam, found {:?}",
|
),
|
||||||
other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n))
|
};
|
||||||
),
|
|
||||||
};
|
let ty_const_params_impl = ty_const_params_of(impl_item.def_id);
|
||||||
let trait_span = match tcx.hir().get_if_local(const_param_trait) {
|
let ty_const_params_trait = ty_const_params_of(trait_item.def_id);
|
||||||
Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span),
|
let assoc_item_str = assoc_item_kind_str(&impl_item);
|
||||||
_ => None,
|
|
||||||
};
|
for (param_impl, param_trait) in iter::zip(ty_const_params_impl, ty_const_params_trait) {
|
||||||
let mut err = struct_span_err!(
|
use GenericParamDefKind::*;
|
||||||
tcx.sess,
|
match (¶m_impl.kind, ¶m_trait.kind) {
|
||||||
*impl_span,
|
(Const { .. }, Const { .. }) => {
|
||||||
E0053,
|
let impl_ty = tcx.type_of(param_impl.def_id);
|
||||||
"method `{}` has an incompatible const parameter type for trait",
|
let trait_ty = tcx.type_of(param_trait.def_id);
|
||||||
trait_m.name
|
if impl_ty != trait_ty {
|
||||||
);
|
let param_impl_span = get_param_span(param_impl).unwrap();
|
||||||
err.span_note(
|
let param_impl_ident = get_param_ident(param_impl);
|
||||||
trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span),
|
let param_trait_span = get_param_span(param_trait);
|
||||||
&format!(
|
|
||||||
"the const parameter{} has type `{}`, but the declaration \
|
let mut err = struct_span_err!(
|
||||||
in trait `{}` has type `{}`",
|
tcx.sess,
|
||||||
&impl_ident.map_or_else(|| "".to_string(), |ident| format!(" `{ident}`")),
|
*param_impl_span,
|
||||||
impl_ty,
|
E0053,
|
||||||
tcx.def_path_str(trait_m.def_id),
|
"{} `{}` has an incompatible const parameter type for trait",
|
||||||
trait_ty
|
assoc_item_str,
|
||||||
),
|
trait_item.name,
|
||||||
);
|
);
|
||||||
let reported = err.emit();
|
err.span_note(
|
||||||
return Err(reported);
|
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 `{}`",
|
||||||
|
¶m_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",
|
||||||
|
¶m_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 `{}`",
|
||||||
|
¶m_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);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1095,6 +1198,8 @@ crate fn compare_ty_impl<'tcx>(
|
|||||||
let _: Result<(), ErrorGuaranteed> = (|| {
|
let _: Result<(), ErrorGuaranteed> = (|| {
|
||||||
compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
|
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)?;
|
||||||
|
|
||||||
let sp = tcx.def_span(impl_ty.def_id);
|
let sp = tcx.def_span(impl_ty.def_id);
|
||||||
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
|
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
|
||||||
|
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
trait Trait {
|
||||||
|
fn foo<U>() {}
|
||||||
|
}
|
||||||
|
impl Trait for () {
|
||||||
|
fn foo<const M: u64>() {}
|
||||||
|
//~^ error: method `foo` has an incompatble generic parameter for trait
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Other {
|
||||||
|
fn bar<const M: u8>() {}
|
||||||
|
}
|
||||||
|
impl Other for () {
|
||||||
|
fn bar<T>() {}
|
||||||
|
//~^ error: method `bar` has an incompatible generic parameter for trait
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Uwu {
|
||||||
|
fn baz<const N: u32>() {}
|
||||||
|
}
|
||||||
|
impl Uwu for () {
|
||||||
|
fn baz<const N: i32>() {}
|
||||||
|
//~^ error: method `baz` has an incompatible generic parameter for trait
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,52 @@
|
|||||||
|
error[E0049]: method `foo` has 0 type parameters but its trait declaration has 1 type parameter
|
||||||
|
--> $DIR/mismatched_ty_const_in_trait_impl.rs:5:12
|
||||||
|
|
|
||||||
|
LL | fn foo<U>() {}
|
||||||
|
| - expected 1 type parameter
|
||||||
|
...
|
||||||
|
LL | fn foo<const M: u64>() {}
|
||||||
|
| ^^^^^^^^^^^^ found 0 type parameters
|
||||||
|
|
||||||
|
error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
|
||||||
|
--> $DIR/mismatched_ty_const_in_trait_impl.rs:5:12
|
||||||
|
|
|
||||||
|
LL | fn foo<U>() {}
|
||||||
|
| - expected 0 const parameters
|
||||||
|
...
|
||||||
|
LL | fn foo<const M: u64>() {}
|
||||||
|
| ^^^^^^^^^^^^ found 1 const parameter
|
||||||
|
|
||||||
|
error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters
|
||||||
|
--> $DIR/mismatched_ty_const_in_trait_impl.rs:13:12
|
||||||
|
|
|
||||||
|
LL | fn bar<const M: u8>() {}
|
||||||
|
| ----------- expected 0 type parameters
|
||||||
|
...
|
||||||
|
LL | fn bar<T>() {}
|
||||||
|
| ^ found 1 type parameter
|
||||||
|
|
||||||
|
error[E0049]: method `bar` has 0 const parameters but its trait declaration has 1 const parameter
|
||||||
|
--> $DIR/mismatched_ty_const_in_trait_impl.rs:13:12
|
||||||
|
|
|
||||||
|
LL | fn bar<const M: u8>() {}
|
||||||
|
| ----------- expected 1 const parameter
|
||||||
|
...
|
||||||
|
LL | fn bar<T>() {}
|
||||||
|
| ^ found 0 const parameters
|
||||||
|
|
||||||
|
error[E0053]: method `baz` has an incompatible const parameter type for trait
|
||||||
|
--> $DIR/mismatched_ty_const_in_trait_impl.rs:21:12
|
||||||
|
|
|
||||||
|
LL | fn baz<const N: i32>() {}
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
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 | fn baz<const N: u32>() {}
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0049, E0053.
|
||||||
|
For more information about an error, try `rustc --explain E0049`.
|
@ -0,0 +1,12 @@
|
|||||||
|
#![feature(generic_associated_types)]
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Foo<const N: u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for () {
|
||||||
|
type Foo<const N: u64> = u32;
|
||||||
|
//~^ error: associated type `Foo` has an incompatible const parameter type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,15 @@
|
|||||||
|
error[E0053]: associated type `Foo` has an incompatible const parameter type for trait
|
||||||
|
--> $DIR/const_params_have_right_type.rs:8:14
|
||||||
|
|
|
||||||
|
LL | type Foo<const N: u64> = u32;
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the const parameter `N` has type `u64`, but the declaration in trait `Trait::Foo` has type `u8`
|
||||||
|
--> $DIR/const_params_have_right_type.rs:4:14
|
||||||
|
|
|
||||||
|
LL | type Foo<const N: u8>;
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0053`.
|
Loading…
x
Reference in New Issue
Block a user