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 a `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.
20 /// Assumes that this is run after the entire crate has been successfully type-checked.
21 pub fn codegen_fulfill_obligation
<'tcx
>(
23 (param_env
, trait_ref
): (ty
::ParamEnv
<'tcx
>, ty
::PolyTraitRef
<'tcx
>),
24 ) -> Result
<ImplSource
<'tcx
, ()>, ErrorReported
> {
25 // Remove any references to regions; this helps improve caching.
26 let trait_ref
= ty
.erase_regions(&trait_ref
);
29 "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
30 (param_env
, trait_ref
),
34 // Do the initial selection for the obligation. This yields the
35 // shallow result we are looking for -- that is, what specific impl.
36 ty
.infer_ctxt().enter(|infcx
| {
37 let mut selcx
= SelectionContext
::new(&infcx
);
39 let obligation_cause
= ObligationCause
::dummy();
41 Obligation
::new(obligation_cause
, param_env
, trait_ref
.to_poly_trait_predicate());
43 let selection
= match selcx
.select(&obligation
) {
44 Ok(Some(selection
)) => selection
,
46 // Ambiguity can happen when monomorphizing during trans
47 // expands to some humongo type that never occurred
48 // statically -- this humongo type can then overflow,
49 // leading to an ambiguous result. So report this as an
50 // overflow bug, since I believe this is the only case
51 // where ambiguity can result.
52 infcx
.tcx
.sess
.delay_span_bug(
55 "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
56 overflow or prior type error",
60 return Err(ErrorReported
);
62 Err(Unimplemented
) => {
63 // This can trigger when we probe for the source of a `'static` lifetime requirement
64 // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
65 infcx
.tcx
.sess
.delay_span_bug(
68 "Encountered error `Unimplemented` selecting `{:?}` during codegen",
72 return Err(ErrorReported
);
75 bug
!("Encountered error `{:?}` selecting `{:?}` during codegen", e
, trait_ref
)
79 debug
!("fulfill_obligation: selection={:?}", selection
);
81 // Currently, we use a fulfillment context to completely resolve
82 // all nested obligations. This is because they can inform the
83 // inference of the impl's type parameters.
84 let mut fulfill_cx
= FulfillmentContext
::new();
85 let impl_source
= selection
.map(|predicate
| {
86 debug
!("fulfill_obligation: register_predicate_obligation {:?}", predicate
);
87 fulfill_cx
.register_predicate_obligation(&infcx
, predicate
);
89 let impl_source
= drain_fulfillment_cx_or_panic(&infcx
, &mut fulfill_cx
, &impl_source
);
91 info
!("Cache miss: {:?} => {:?}", trait_ref
, impl_source
);
98 /// Finishes processes any obligations that remain in the
99 /// fulfillment context, and then returns the result with all type
100 /// variables removed and regions erased. Because this is intended
101 /// for use after type-check has completed, if any errors occur,
102 /// it will panic. It is used during normalization and other cases
103 /// where processing the obligations in `fulfill_cx` may cause
104 /// type inference variables that appear in `result` to be
105 /// unified, and hence we need to process those obligations to get
106 /// the complete picture of the type.
107 fn drain_fulfillment_cx_or_panic
<T
>(
108 infcx
: &InferCtxt
<'_
, 'tcx
>,
109 fulfill_cx
: &mut FulfillmentContext
<'tcx
>,
113 T
: TypeFoldable
<'tcx
>,
115 debug
!("drain_fulfillment_cx_or_panic()");
117 // In principle, we only need to do this so long as `result`
118 // contains unbound type parameters. It could be a slight
119 // optimization to stop iterating early.
120 if let Err(errors
) = fulfill_cx
.select_all_or_error(infcx
) {
121 infcx
.tcx
.sess
.delay_span_bug(
122 rustc_span
::DUMMY_SP
,
123 &format
!("Encountered errors `{:?}` resolving bounds after type-checking", errors
),
127 let result
= infcx
.resolve_vars_if_possible(result
);
128 infcx
.tcx
.erase_regions(&result
)