Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions compiler/rustc_typeck/src/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
Expand Down Expand Up @@ -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,
Expand Down
25 changes: 25 additions & 0 deletions src/test/ui/const-generics/issue-86820.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions src/test/ui/const-generics/issue-86820.stderr
Original file line number Diff line number Diff line change
@@ -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`.