2018-05-08 16:10:16 +03:00
|
|
|
// This file contains various trait resolution methods used by codegen.
|
2017-04-21 21:02:14 -04:00
|
|
|
// They all assume regions can be erased and monomorphic types. It
|
|
|
|
// seems likely that they should eventually be merged into more
|
|
|
|
// general routines.
|
|
|
|
|
2020-01-06 20:13:24 +01:00
|
|
|
use crate::infer::{InferCtxt, TyCtxtInferExt};
|
2019-12-22 17:42:04 -05:00
|
|
|
use crate::traits::{
|
2020-05-11 15:25:33 +00:00
|
|
|
FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
|
2020-06-30 17:41:15 -07:00
|
|
|
Unimplemented,
|
2019-12-22 17:42:04 -05:00
|
|
|
};
|
2020-04-10 05:13:29 +03:00
|
|
|
use rustc_errors::ErrorReported;
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::ty::fold::TypeFoldable;
|
|
|
|
use rustc_middle::ty::{self, TyCtxt};
|
2017-04-21 21:02:14 -04:00
|
|
|
|
2020-05-11 15:25:33 +00:00
|
|
|
/// Attempts to resolve an obligation to a `ImplSource`. The result is
|
|
|
|
/// a shallow `ImplSource` resolution, meaning that we do not
|
2017-09-28 23:13:43 -04:00
|
|
|
/// (necessarily) resolve all nested obligations on the impl. Note
|
|
|
|
/// that type check should guarantee to us that all nested
|
|
|
|
/// obligations *could be* resolved if we wanted to.
|
|
|
|
/// Assumes that this is run after the entire crate has been successfully type-checked.
|
2019-06-12 00:11:55 +03:00
|
|
|
pub fn codegen_fulfill_obligation<'tcx>(
|
2020-09-28 20:56:52 +02:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2019-06-12 00:11:55 +03:00
|
|
|
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
|
2020-05-11 15:25:33 +00:00
|
|
|
) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
|
2020-09-28 20:56:52 +02:00
|
|
|
// Remove any references to regions and normalize; this helps improve caching.
|
|
|
|
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
|
2017-09-28 23:13:43 -04:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
debug!(
|
|
|
|
"codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
|
|
|
|
(param_env, trait_ref),
|
|
|
|
trait_ref.def_id()
|
|
|
|
);
|
2017-09-28 23:13:43 -04:00
|
|
|
|
|
|
|
// Do the initial selection for the obligation. This yields the
|
|
|
|
// shallow result we are looking for -- that is, what specific impl.
|
2020-09-28 20:56:52 +02:00
|
|
|
tcx.infer_ctxt().enter(|infcx| {
|
2017-09-28 23:13:43 -04:00
|
|
|
let mut selcx = SelectionContext::new(&infcx);
|
|
|
|
|
|
|
|
let obligation_cause = ObligationCause::dummy();
|
2019-12-22 17:42:04 -05:00
|
|
|
let obligation =
|
|
|
|
Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
|
2017-09-28 23:13:43 -04:00
|
|
|
|
|
|
|
let selection = match selcx.select(&obligation) {
|
|
|
|
Ok(Some(selection)) => selection,
|
|
|
|
Ok(None) => {
|
|
|
|
// Ambiguity can happen when monomorphizing during trans
|
|
|
|
// expands to some humongo type that never occurred
|
|
|
|
// statically -- this humongo 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.
|
2020-03-01 10:46:07 -08:00
|
|
|
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
|
|
|
|
),
|
|
|
|
);
|
2020-04-10 05:13:29 +03:00
|
|
|
return Err(ErrorReported);
|
2017-09-28 23:13:43 -04:00
|
|
|
}
|
2020-06-30 17:41:15 -07:00
|
|
|
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.
|
|
|
|
infcx.tcx.sess.delay_span_bug(
|
|
|
|
rustc_span::DUMMY_SP,
|
|
|
|
&format!(
|
|
|
|
"Encountered error `Unimplemented` selecting `{:?}` during codegen",
|
|
|
|
trait_ref
|
|
|
|
),
|
|
|
|
);
|
|
|
|
return Err(ErrorReported);
|
|
|
|
}
|
2017-09-28 23:13:43 -04:00
|
|
|
Err(e) => {
|
2018-09-12 16:57:19 +02:00
|
|
|
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
|
2017-09-28 23:13:43 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
debug!("fulfill_obligation: selection={:?}", selection);
|
|
|
|
|
|
|
|
// Currently, we use a fulfillment context to completely resolve
|
|
|
|
// all nested obligations. This is because they can inform the
|
|
|
|
// inference of the impl's type parameters.
|
|
|
|
let mut fulfill_cx = FulfillmentContext::new();
|
2020-05-11 15:25:33 +00:00
|
|
|
let impl_source = selection.map(|predicate| {
|
2017-09-28 23:13:43 -04:00
|
|
|
debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
|
|
|
|
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
|
|
|
});
|
2020-05-11 15:25:33 +00:00
|
|
|
let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source);
|
2017-09-28 23:13:43 -04:00
|
|
|
|
2020-05-11 15:25:33 +00:00
|
|
|
info!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
|
|
|
|
Ok(impl_source)
|
2017-09-28 23:13:43 -04:00
|
|
|
})
|
|
|
|
}
|
2017-04-21 21:02:14 -04:00
|
|
|
|
2017-04-17 12:35:53 -04:00
|
|
|
// # Global Cache
|
|
|
|
|
2020-02-22 11:44:18 +01:00
|
|
|
/// 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 after type-check has completed, 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<T>(
|
|
|
|
infcx: &InferCtxt<'_, 'tcx>,
|
|
|
|
fulfill_cx: &mut FulfillmentContext<'tcx>,
|
|
|
|
result: &T,
|
|
|
|
) -> T
|
|
|
|
where
|
|
|
|
T: TypeFoldable<'tcx>,
|
|
|
|
{
|
|
|
|
debug!("drain_fulfillment_cx_or_panic()");
|
2018-02-13 09:15:01 -05:00
|
|
|
|
2020-02-22 11:44:18 +01:00
|
|
|
// 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.
|
|
|
|
if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
|
|
|
|
bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
|
2018-02-13 09:15:01 -05:00
|
|
|
}
|
2020-02-22 11:44:18 +01:00
|
|
|
|
|
|
|
let result = infcx.resolve_vars_if_possible(result);
|
|
|
|
infcx.tcx.erase_regions(&result)
|
2018-02-13 09:15:01 -05:00
|
|
|
}
|