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, TyCtxtInferExt};
8 FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
11 use rustc_errors::ErrorReported;
12 use rustc_middle::ty::fold::TypeFoldable;
13 use rustc_middle::ty::{self, TyCtxt};
15 /// Attempts to resolve an obligation to an `ImplSource`. The result is
16 /// a shallow `ImplSource` resolution, meaning that we do not
17 /// (necessarily) resolve all nested obligations on the impl. Note
18 /// that type check should guarantee to us that all nested
19 /// obligations *could be* resolved if we wanted to.
21 /// This also expects that `trait_ref` is fully normalized.
22 pub fn codegen_fulfill_obligation<'tcx>(
24 (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
25 ) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorReported> {
26 // Remove any references to regions; this helps improve caching.
27 let trait_ref = tcx.erase_regions(trait_ref);
28 // We expect the input to be fully normalized.
29 debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
31 "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
32 (param_env, trait_ref),
36 // Do the initial selection for the obligation. This yields the
37 // shallow result we are looking for -- that is, what specific impl.
38 tcx.infer_ctxt().enter(|infcx| {
39 let mut selcx = SelectionContext::new(&infcx);
41 let obligation_cause = ObligationCause::dummy();
43 Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
45 let selection = match selcx.select(&obligation) {
46 Ok(Some(selection)) => selection,
48 // Ambiguity can happen when monomorphizing during trans
49 // expands to some humongo type that never occurred
50 // statically -- this humongo type can then overflow,
51 // leading to an ambiguous result. So report this as an
52 // overflow bug, since I believe this is the only case
53 // where ambiguity can result.
54 infcx.tcx.sess.delay_span_bug(
57 "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
58 overflow or prior type error",
62 return Err(ErrorReported);
64 Err(Unimplemented) => {
65 // This can trigger when we probe for the source of a `'static` lifetime requirement
66 // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
67 // This can also trigger when we have a global bound that is not actually satisfied,
68 // but was included during typeck due to the trivial_bounds feature.
69 infcx.tcx.sess.delay_span_bug(
72 "Encountered error `Unimplemented` selecting `{:?}` during codegen",
76 return Err(ErrorReported);
79 bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
83 debug!("fulfill_obligation: selection={:?}", selection);
85 // Currently, we use a fulfillment context to completely resolve
86 // all nested obligations. This is because they can inform the
87 // inference of the impl's type parameters.
88 let mut fulfill_cx = FulfillmentContext::new();
89 let impl_source = selection.map(|predicate| {
90 debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
91 fulfill_cx.register_predicate_obligation(&infcx, predicate);
93 let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
95 debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
96 Ok(&*tcx.arena.alloc(impl_source))
102 /// Finishes processes any obligations that remain in the
103 /// fulfillment context, and then returns the result with all type
104 /// variables removed and regions erased. Because this is intended
105 /// for use outside of type inference, if any errors occur,
106 /// it will panic. It is used during normalization and other cases
107 /// where processing the obligations in `fulfill_cx` may cause
108 /// type inference variables that appear in `result` to be
109 /// unified, and hence we need to process those obligations to get
110 /// the complete picture of the type.
111 fn drain_fulfillment_cx_or_panic<'tcx, T>(
112 infcx: &InferCtxt<'_, 'tcx>,
113 fulfill_cx: &mut FulfillmentContext<'tcx>,
117 T: TypeFoldable<'tcx>,
119 debug!("drain_fulfillment_cx_or_panic()");
121 // In principle, we only need to do this so long as `result`
122 // contains unbound type parameters. It could be a slight
123 // optimization to stop iterating early.
124 let errors = fulfill_cx.select_all_or_error(infcx);
125 if !errors.is_empty() {
126 infcx.tcx.sess.delay_span_bug(
127 rustc_span::DUMMY_SP,
129 "Encountered errors `{:?}` resolving bounds outside of type inference",
135 let result = infcx.resolve_vars_if_possible(result);
136 infcx.tcx.erase_regions(result)