Gracefully fail to resolve associated items instead of delay_span_bug
.
This commit is contained in:
parent
532be942dd
commit
6cfe52c094
11 changed files with 99 additions and 87 deletions
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue