1 // This file contains various trait resolution methods used by codegen.
2 // They all assume regions can be erased and monomorphic types. It
3 // seems likely that they should eventually be merged into more
6 use crate::infer::InferCtxt;
8 FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable,
10 use crate::ty::fold::TypeFoldable;
11 use crate::ty::subst::{Subst, SubstsRef};
12 use crate::ty::{self, TyCtxt};
14 /// Attempts to resolve an obligation to a vtable. The result is
15 /// a shallow vtable resolution, meaning that we do not
16 /// (necessarily) resolve all nested obligations on the impl. Note
17 /// that type check should guarantee to us that all nested
18 /// obligations *could be* resolved if we wanted to.
19 /// Assumes that this is run after the entire crate has been successfully type-checked.
20 pub fn codegen_fulfill_obligation<'tcx>(
22 (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
23 ) -> Vtable<'tcx, ()> {
24 // Remove any references to regions; this helps improve caching.
25 let trait_ref = ty.erase_regions(&trait_ref);
28 "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
29 (param_env, trait_ref),
33 // Do the initial selection for the obligation. This yields the
34 // shallow result we are looking for -- that is, what specific impl.
35 ty.infer_ctxt().enter(|infcx| {
36 let mut selcx = SelectionContext::new(&infcx);
38 let obligation_cause = ObligationCause::dummy();
40 Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
42 let selection = match selcx.select(&obligation) {
43 Ok(Some(selection)) => selection,
45 // Ambiguity can happen when monomorphizing during trans
46 // expands to some humongo type that never occurred
47 // statically -- this humongo type can then overflow,
48 // leading to an ambiguous result. So report this as an
49 // overflow bug, since I believe this is the only case
50 // where ambiguity can result.
52 "Encountered ambiguity selecting `{:?}` during codegen, \
53 presuming due to overflow",
58 bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
62 debug!("fulfill_obligation: selection={:?}", selection);
64 // Currently, we use a fulfillment context to completely resolve
65 // all nested obligations. This is because they can inform the
66 // inference of the impl's type parameters.
67 let mut fulfill_cx = FulfillmentContext::new();
68 let vtable = selection.map(|predicate| {
69 debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
70 fulfill_cx.register_predicate_obligation(&infcx, predicate);
72 let vtable = infcx.drain_fulfillment_cx_or_panic(&mut fulfill_cx, &vtable);
74 info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
79 impl<'tcx> TyCtxt<'tcx> {
80 /// Monomorphizes a type from the AST by first applying the
81 /// in-scope substitutions and then normalizing any associated
83 pub fn subst_and_normalize_erasing_regions<T>(
85 param_substs: SubstsRef<'tcx>,
86 param_env: ty::ParamEnv<'tcx>,
90 T: TypeFoldable<'tcx>,
93 "subst_and_normalize_erasing_regions(\
97 param_substs, value, param_env,
99 let substituted = value.subst(self, param_substs);
100 self.normalize_erasing_regions(param_env, substituted)
106 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
107 /// Finishes processes any obligations that remain in the
108 /// fulfillment context, and then returns the result with all type
109 /// variables removed and regions erased. Because this is intended
110 /// for use after type-check has completed, if any errors occur,
111 /// it will panic. It is used during normalization and other cases
112 /// where processing the obligations in `fulfill_cx` may cause
113 /// type inference variables that appear in `result` to be
114 /// unified, and hence we need to process those obligations to get
115 /// the complete picture of the type.
116 fn drain_fulfillment_cx_or_panic<T>(
118 fulfill_cx: &mut FulfillmentContext<'tcx>,
122 T: TypeFoldable<'tcx>,
124 debug!("drain_fulfillment_cx_or_panic()");
126 // In principle, we only need to do this so long as `result`
127 // contains unbound type parameters. It could be a slight
128 // optimization to stop iterating early.
129 if let Err(errors) = fulfill_cx.select_all_or_error(self) {
130 bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
133 let result = self.resolve_vars_if_possible(result);
134 self.tcx.erase_regions(&result)