Rollup merge of #86843 - FabianWolff:issue-86820, r=lcnr
Check that const parameters of trait methods have compatible types This PR fixes #86820. The problem is that this currently passes the type checker: ```rust trait Tr { fn foo<const N: u8>(self) -> u8; } impl Tr for f32 { fn foo<const N: bool>(self) -> u8 { 42 } } ``` i.e. the type checker fails to check whether const parameters in `impl` methods have the same type as the corresponding declaration in the trait. With my changes, I get, for the above code: ``` error[E0053]: method `foo` has an incompatible const parameter type for trait --> test.rs:6:18 | 6 | fn foo<const N: bool>(self) -> u8 { 42 } | ^ | note: the const parameter `N` has type `bool`, but the declaration in trait `Tr::foo` has type `u8` --> test.rs:2:18 | 2 | fn foo<const N: u8>(self) -> u8; | ^ error: aborting due to previous error ``` This fixes #86820, where an ICE happens later on because the trait method is declared with a const parameter of type `u8`, but the `impl` uses one of type `usize`: > `expected int of size 8, but got size 1`
This commit is contained in:
commit
783efd29ae
3 changed files with 106 additions and 0 deletions
|
@ -66,6 +66,10 @@ crate fn compare_impl_method<'tcx>(
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(ErrorReported) = compare_const_param_types(tcx, impl_m, trait_m, trait_item_span) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compare_predicate_entailment<'tcx>(
|
fn compare_predicate_entailment<'tcx>(
|
||||||
|
@ -929,6 +933,68 @@ fn compare_synthetic_generics<'tcx>(
|
||||||
if error_found { Err(ErrorReported) } else { Ok(()) }
|
if error_found { Err(ErrorReported) } else { Ok(()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compare_const_param_types<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
impl_m: &ty::AssocItem,
|
||||||
|
trait_m: &ty::AssocItem,
|
||||||
|
trait_item_span: Option<Span>,
|
||||||
|
) -> Result<(), ErrorReported> {
|
||||||
|
let const_params_of = |def_id| {
|
||||||
|
tcx.generics_of(def_id).params.iter().filter_map(|param| match param.kind {
|
||||||
|
GenericParamDefKind::Const { .. } => Some(param.def_id),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
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 impl_ty = tcx.type_of(const_param_impl);
|
||||||
|
let trait_ty = tcx.type_of(const_param_trait);
|
||||||
|
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, .. })) => (
|
||||||
|
span,
|
||||||
|
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 trait_span = match tcx.hir().get_if_local(const_param_trait) {
|
||||||
|
Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
*impl_span,
|
||||||
|
E0053,
|
||||||
|
"method `{}` has an incompatible const parameter type for trait",
|
||||||
|
trait_m.ident
|
||||||
|
);
|
||||||
|
err.span_note(
|
||||||
|
trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span),
|
||||||
|
&format!(
|
||||||
|
"the const parameter{} has type `{}`, but the declaration \
|
||||||
|
in trait `{}` has type `{}`",
|
||||||
|
&impl_ident.map_or_else(|| "".to_string(), |ident| format!(" `{}`", ident)),
|
||||||
|
impl_ty,
|
||||||
|
tcx.def_path_str(trait_m.def_id),
|
||||||
|
trait_ty
|
||||||
|
),
|
||||||
|
);
|
||||||
|
err.emit();
|
||||||
|
return Err(ErrorReported);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
crate fn compare_const_impl<'tcx>(
|
crate fn compare_const_impl<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impl_c: &ty::AssocItem,
|
impl_c: &ty::AssocItem,
|
||||||
|
|
25
src/test/ui/const-generics/issue-86820.rs
Normal file
25
src/test/ui/const-generics/issue-86820.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// Regression test for the ICE described in #86820.
|
||||||
|
|
||||||
|
#![allow(unused,dead_code)]
|
||||||
|
use std::ops::BitAnd;
|
||||||
|
|
||||||
|
const C: fn() = || is_set();
|
||||||
|
fn is_set() {
|
||||||
|
0xffu8.bit::<0>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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`
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bits for u8 {
|
||||||
|
fn bit<const I : usize>(self) -> bool {
|
||||||
|
//~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053]
|
||||||
|
let i = 1 << I;
|
||||||
|
let mask = u8::from(i);
|
||||||
|
mask & self == mask
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
15
src/test/ui/const-generics/issue-86820.stderr
Normal file
15
src/test/ui/const-generics/issue-86820.stderr
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0053]: method `bit` has an incompatible const parameter type for trait
|
||||||
|
--> $DIR/issue-86820.rs:17:18
|
||||||
|
|
|
||||||
|
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:18
|
||||||
|
|
|
||||||
|
LL | fn bit<const I : u8>(self) -> bool;
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0053`.
|
Loading…
Add table
Add a link
Reference in a new issue