mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-02 10:04:23 +00:00
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
@ -66,6 +66,10 @@ crate fn compare_impl_method<'tcx>(
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(ErrorReported) = compare_const_param_types(tcx, impl_m, trait_m, trait_item_span) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_predicate_entailment<'tcx>(
|
||||
@ -929,6 +933,68 @@ fn compare_synthetic_generics<'tcx>(
|
||||
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>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
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…
Reference in New Issue
Block a user