Skip to content

Commit 9b874c4

Browse files
committed
Check that const parameters of trait methods have compatible types
1 parent a8b8558 commit 9b874c4

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

compiler/rustc_typeck/src/check/compare_method.rs

+66
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ crate fn compare_impl_method<'tcx>(
6666
{
6767
return;
6868
}
69+
70+
if let Err(ErrorReported) = compare_const_param_types(tcx, impl_m, trait_m, trait_item_span) {
71+
return;
72+
}
6973
}
7074

7175
fn compare_predicate_entailment<'tcx>(
@@ -929,6 +933,68 @@ fn compare_synthetic_generics<'tcx>(
929933
if error_found { Err(ErrorReported) } else { Ok(()) }
930934
}
931935

936+
fn compare_const_param_types<'tcx>(
937+
tcx: TyCtxt<'tcx>,
938+
impl_m: &ty::AssocItem,
939+
trait_m: &ty::AssocItem,
940+
trait_item_span: Option<Span>,
941+
) -> Result<(), ErrorReported> {
942+
let const_params_of = |def_id| {
943+
tcx.generics_of(def_id).params.iter().filter_map(|param| match param.kind {
944+
GenericParamDefKind::Const { .. } => Some(param.def_id),
945+
_ => None,
946+
})
947+
};
948+
let const_params_impl = const_params_of(impl_m.def_id);
949+
let const_params_trait = const_params_of(trait_m.def_id);
950+
951+
for (const_param_impl, const_param_trait) in iter::zip(const_params_impl, const_params_trait) {
952+
let impl_ty = tcx.type_of(const_param_impl);
953+
let trait_ty = tcx.type_of(const_param_trait);
954+
if impl_ty != trait_ty {
955+
let (impl_span, impl_ident) = match tcx.hir().get_if_local(const_param_impl) {
956+
Some(hir::Node::GenericParam(hir::GenericParam { span, name, .. })) => (
957+
span,
958+
match name {
959+
hir::ParamName::Plain(ident) => Some(ident),
960+
_ => None,
961+
},
962+
),
963+
other => bug!(
964+
"expected GenericParam, found {:?}",
965+
other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n))
966+
),
967+
};
968+
let trait_span = match tcx.hir().get_if_local(const_param_trait) {
969+
Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span),
970+
_ => None,
971+
};
972+
let mut err = struct_span_err!(
973+
tcx.sess,
974+
*impl_span,
975+
E0053,
976+
"method `{}` has an incompatible const parameter type for trait",
977+
trait_m.ident
978+
);
979+
err.span_note(
980+
trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span),
981+
&format!(
982+
"the const parameter{} has type `{}`, but the declaration \
983+
in trait `{}` has type `{}`",
984+
&impl_ident.map_or_else(|| "".to_string(), |ident| format!(" `{}`", ident)),
985+
impl_ty,
986+
tcx.def_path_str(trait_m.def_id),
987+
trait_ty
988+
),
989+
);
990+
err.emit();
991+
return Err(ErrorReported);
992+
}
993+
}
994+
995+
Ok(())
996+
}
997+
932998
crate fn compare_const_impl<'tcx>(
933999
tcx: TyCtxt<'tcx>,
9341000
impl_c: &ty::AssocItem,
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Regression test for the ICE described in #86820.
2+
3+
#![allow(unused,dead_code)]
4+
use std::ops::BitAnd;
5+
6+
const C: fn() = || is_set();
7+
fn is_set() {
8+
0xffu8.bit::<0>();
9+
}
10+
11+
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`
14+
}
15+
16+
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]
19+
let i = 1 << I;
20+
let mask = u8::from(i);
21+
mask & self == mask
22+
}
23+
}
24+
25+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0053]: method `bit` has an incompatible const parameter type for trait
2+
--> $DIR/issue-86820.rs:17:18
3+
|
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:18
9+
|
10+
LL | fn bit<const I : u8>(self) -> bool;
11+
| ^
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0053`.

0 commit comments

Comments
 (0)