1
Fork 0

Gracefully fail to resolve associated items instead of delay_span_bug.

This commit is contained in:
Camille GILLOT 2022-05-01 11:03:14 +02:00
parent 532be942dd
commit 6cfe52c094
11 changed files with 99 additions and 87 deletions

View file

@ -3,13 +3,12 @@
// seems likely that they should eventually be merged into more
// general routines.
use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::infer::TyCtxtInferExt;
use crate::traits::{
FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
Unimplemented,
};
use rustc_errors::ErrorGuaranteed;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::traits::CodegenObligationError;
use rustc_middle::ty::{self, TyCtxt};
/// Attempts to resolve an obligation to an `ImplSource`. The result is
@ -23,7 +22,7 @@ use rustc_middle::ty::{self, TyCtxt};
pub fn codegen_fulfill_obligation<'tcx>(
tcx: TyCtxt<'tcx>,
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> {
) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
// Remove any references to regions; this helps improve caching.
let trait_ref = tcx.erase_regions(trait_ref);
// We expect the input to be fully normalized.
@ -40,37 +39,8 @@ pub fn codegen_fulfill_obligation<'tcx>(
let selection = match selcx.select(&obligation) {
Ok(Some(selection)) => selection,
Ok(None) => {
// Ambiguity can happen when monomorphizing during trans
// expands to some humongous type that never occurred
// statically -- this humongous type can then overflow,
// leading to an ambiguous result. So report this as an
// overflow bug, since I believe this is the only case
// where ambiguity can result.
let reported = infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!(
"encountered ambiguity selecting `{:?}` during codegen, presuming due to \
overflow or prior type error",
trait_ref
),
);
return Err(reported);
}
Err(Unimplemented) => {
// This can trigger when we probe for the source of a `'static` lifetime requirement
// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
// This can also trigger when we have a global bound that is not actually satisfied,
// but was included during typeck due to the trivial_bounds feature.
let guar = infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!(
"Encountered error `Unimplemented` selecting `{:?}` during codegen",
trait_ref
),
);
return Err(guar);
}
Ok(None) => return Err(CodegenObligationError::Ambiguity),
Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
Err(e) => {
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
}
@ -85,7 +55,17 @@ pub fn codegen_fulfill_obligation<'tcx>(
let impl_source = selection.map(|predicate| {
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
// In principle, we only need to do this so long as `impl_source`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
let errors = fulfill_cx.select_all_or_error(&infcx);
if !errors.is_empty() {
return Err(CodegenObligationError::FulfillmentError);
}
let impl_source = infcx.resolve_vars_if_possible(impl_source);
let impl_source = infcx.tcx.erase_regions(impl_source);
// Opaque types may have gotten their hidden types constrained, but we can ignore them safely
// as they will get constrained elsewhere, too.
@ -95,42 +75,3 @@ pub fn codegen_fulfill_obligation<'tcx>(
Ok(&*tcx.arena.alloc(impl_source))
})
}
// # Global Cache
/// Finishes processes any obligations that remain in the
/// fulfillment context, and then returns the result with all type
/// variables removed and regions erased. Because this is intended
/// for use outside of type inference, if any errors occur,
/// it will panic. It is used during normalization and other cases
/// where processing the obligations in `fulfill_cx` may cause
/// type inference variables that appear in `result` to be
/// unified, and hence we need to process those obligations to get
/// the complete picture of the type.
fn drain_fulfillment_cx_or_panic<'tcx, T>(
infcx: &InferCtxt<'_, 'tcx>,
fulfill_cx: &mut FulfillmentContext<'tcx>,
result: T,
) -> T
where
T: TypeFoldable<'tcx>,
{
debug!("drain_fulfillment_cx_or_panic()");
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
let errors = fulfill_cx.select_all_or_error(infcx);
if !errors.is_empty() {
infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!(
"Encountered errors `{:?}` resolving bounds outside of type inference",
errors
),
);
}
let result = infcx.resolve_vars_if_possible(result);
infcx.tcx.erase_regions(result)
}