Skip to content

Commit e95a7bb

Browse files
Fix issue 2589 (rust-lang#2787)
Co-authored-by: Felipe R. Monteiro <[email protected]>
1 parent c7c0f18 commit e95a7bb

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

kani-compiler/src/kani_middle/reachability.rs

+56-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//! - For every static, collect initializer and drop functions.
1414
//!
1515
//! We have kept this module agnostic of any Kani code in case we can contribute this back to rustc.
16+
use rustc_span::ErrorGuaranteed;
1617
use tracing::{debug, debug_span, trace, warn};
1718

1819
use rustc_data_structures::fingerprint::Fingerprint;
@@ -26,6 +27,7 @@ use rustc_middle::mir::mono::MonoItem;
2627
use rustc_middle::mir::visit::Visitor as MirVisitor;
2728
use rustc_middle::mir::{
2829
Body, CastKind, Constant, ConstantKind, Location, Rvalue, Terminator, TerminatorKind,
30+
UnevaluatedConst,
2931
};
3032
use rustc_middle::span_bug;
3133
use rustc_middle::ty::adjustment::PointerCoercion;
@@ -458,7 +460,23 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MonoItemsFnCollector<'a, 'tcx> {
458460
// The `monomorphize` call should have evaluated that constant already.
459461
Ok(const_val) => const_val,
460462
Err(ErrorHandled::TooGeneric(span)) => {
461-
span_bug!(span, "Unexpected polymorphic constant: {:?}", literal)
463+
if graceful_const_resolution_err(
464+
self.tcx,
465+
&un_eval,
466+
span,
467+
self.instance.def_id(),
468+
)
469+
.is_some()
470+
{
471+
return;
472+
} else {
473+
span_bug!(
474+
span,
475+
"Unexpected polymorphic constant: {:?} {:?}",
476+
literal,
477+
constant.literal
478+
)
479+
}
462480
}
463481
Err(error) => {
464482
warn!(?error, "Error already reported");
@@ -494,6 +512,12 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MonoItemsFnCollector<'a, 'tcx> {
494512
// implement the same traits as those in the
495513
// original function/method. A trait mismatch shows
496514
// up here, when we try to resolve a trait method
515+
516+
// FIXME: This assumes the type resolving the
517+
// trait is the first argument, but that isn't
518+
// necessarily true. It could be any argument or
519+
// even the return type, for instance for a
520+
// trait like `FromIterator`.
497521
let generic_ty = outer_args[0].ty(self.body, tcx).peel_refs();
498522
let receiver_ty = tcx.subst_and_normalize_erasing_regions(
499523
substs,
@@ -508,7 +532,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MonoItemsFnCollector<'a, 'tcx> {
508532
"`{receiver_ty}` doesn't implement \
509533
`{trait_}`. The function `{caller}` \
510534
cannot be stubbed by `{}` due to \
511-
generic bounds not being met.",
535+
generic bounds not being met. Callee: {callee}",
512536
tcx.def_path_str(stub)
513537
),
514538
);
@@ -555,6 +579,36 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MonoItemsFnCollector<'a, 'tcx> {
555579
}
556580
}
557581

582+
/// Try to construct a nice error message when const evaluation fails.
583+
///
584+
/// This function handles the `Trt::CNST` case where there is one trait (`Trt`)
585+
/// which defined a constant `CNST` that we failed to resolve. As such we expect
586+
/// that the trait can be resolved from the constant and that only one generic
587+
/// parameter, the instantiation of `Trt`, is present.
588+
///
589+
/// If these expectations are not met we return `None`. We do not know in what
590+
/// situation that would be the case and if they are even possible.
591+
fn graceful_const_resolution_err<'tcx>(
592+
tcx: TyCtxt<'tcx>,
593+
mono_const: &UnevaluatedConst<'tcx>,
594+
span: rustc_span::Span,
595+
parent_fn: DefId,
596+
) -> Option<ErrorGuaranteed> {
597+
let implementor = match mono_const.args.as_slice() {
598+
[one] => one.as_type(),
599+
_ => None,
600+
}?;
601+
let trait_ = tcx.trait_of_item(mono_const.def)?;
602+
let msg = format!(
603+
"Type `{implementor}` does not implement trait `{}`. \
604+
This is likely because `{}` is used as a stub but its \
605+
generic bounds are not being met.",
606+
tcx.def_path_str(trait_),
607+
tcx.def_path_str(parent_fn)
608+
);
609+
Some(tcx.sess.span_err(span, msg))
610+
}
611+
558612
/// Convert a `MonoItem` into a stable `Fingerprint` which can be used as a stable hash across
559613
/// compilation sessions. This allow us to provide a stable deterministic order to codegen.
560614
fn to_fingerprint(tcx: TyCtxt, item: &MonoItem) -> Fingerprint {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
error: Type `std::string::String` does not implement trait `Dummy`. This is likely because `original` is used as a stub but its generic bounds are not being met.
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
//
4+
// kani-flags: -Z stubbing
5+
6+
fn original<T>() {}
7+
8+
trait Dummy {
9+
const TRUE: bool = true;
10+
}
11+
12+
fn stub<T: Dummy>() {
13+
// Do nothing.
14+
assert!(T::TRUE);
15+
}
16+
17+
#[kani::proof]
18+
#[kani::stub(original, stub)]
19+
fn check_mismatch() {
20+
original::<String>();
21+
}

0 commit comments

Comments
 (0)