]>
Commit | Line | Data |
---|---|---|
94b46f34 | 1 | // This file contains various trait resolution methods used by codegen. |
cc61c64b XL |
2 | // They all assume regions can be erased and monomorphic types. It |
3 | // seems likely that they should eventually be merged into more | |
4 | // general routines. | |
5 | ||
74b04a01 | 6 | use crate::infer::{InferCtxt, TyCtxtInferExt}; |
dfeec247 | 7 | use crate::traits::{ |
f035d41b | 8 | FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, |
3dfed10e | 9 | Unimplemented, |
dfeec247 | 10 | }; |
f9f354fc | 11 | use rustc_errors::ErrorReported; |
ba9703b0 XL |
12 | use rustc_middle::ty::fold::TypeFoldable; |
13 | use rustc_middle::ty::{self, TyCtxt}; | |
cc61c64b | 14 | |
94222f64 | 15 | /// Attempts to resolve an obligation to an `ImplSource`. The result is |
f035d41b | 16 | /// a shallow `ImplSource` resolution, meaning that we do not |
abe05a73 XL |
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. | |
29967ef6 | 20 | /// |
abe05a73 | 21 | /// Assumes that this is run after the entire crate has been successfully type-checked. |
29967ef6 | 22 | /// This also expects that `trait_ref` is fully normalized. |
dc9dc135 | 23 | pub fn codegen_fulfill_obligation<'tcx>( |
29967ef6 | 24 | tcx: TyCtxt<'tcx>, |
dc9dc135 | 25 | (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), |
f035d41b | 26 | ) -> Result<ImplSource<'tcx, ()>, ErrorReported> { |
abe05a73 | 27 | // Remove any references to regions; this helps improve caching. |
fc512014 | 28 | let trait_ref = tcx.erase_regions(trait_ref); |
29967ef6 XL |
29 | // We expect the input to be fully normalized. |
30 | debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref)); | |
dfeec247 XL |
31 | debug!( |
32 | "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", | |
33 | (param_env, trait_ref), | |
34 | trait_ref.def_id() | |
35 | ); | |
abe05a73 XL |
36 | |
37 | // Do the initial selection for the obligation. This yields the | |
38 | // shallow result we are looking for -- that is, what specific impl. | |
29967ef6 | 39 | tcx.infer_ctxt().enter(|infcx| { |
abe05a73 XL |
40 | let mut selcx = SelectionContext::new(&infcx); |
41 | ||
42 | let obligation_cause = ObligationCause::dummy(); | |
dfeec247 XL |
43 | let obligation = |
44 | Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); | |
abe05a73 XL |
45 | |
46 | let selection = match selcx.select(&obligation) { | |
47 | Ok(Some(selection)) => selection, | |
48 | Ok(None) => { | |
49 | // Ambiguity can happen when monomorphizing during trans | |
50 | // expands to some humongo type that never occurred | |
51 | // statically -- this humongo type can then overflow, | |
52 | // leading to an ambiguous result. So report this as an | |
53 | // overflow bug, since I believe this is the only case | |
54 | // where ambiguity can result. | |
74b04a01 XL |
55 | infcx.tcx.sess.delay_span_bug( |
56 | rustc_span::DUMMY_SP, | |
57 | &format!( | |
58 | "encountered ambiguity selecting `{:?}` during codegen, presuming due to \ | |
59 | overflow or prior type error", | |
60 | trait_ref | |
61 | ), | |
62 | ); | |
f9f354fc | 63 | return Err(ErrorReported); |
abe05a73 | 64 | } |
3dfed10e XL |
65 | Err(Unimplemented) => { |
66 | // This can trigger when we probe for the source of a `'static` lifetime requirement | |
67 | // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound. | |
68 | infcx.tcx.sess.delay_span_bug( | |
69 | rustc_span::DUMMY_SP, | |
70 | &format!( | |
71 | "Encountered error `Unimplemented` selecting `{:?}` during codegen", | |
72 | trait_ref | |
73 | ), | |
74 | ); | |
75 | return Err(ErrorReported); | |
76 | } | |
abe05a73 | 77 | Err(e) => { |
0bf4aa26 | 78 | bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) |
abe05a73 XL |
79 | } |
80 | }; | |
81 | ||
82 | debug!("fulfill_obligation: selection={:?}", selection); | |
83 | ||
84 | // Currently, we use a fulfillment context to completely resolve | |
85 | // all nested obligations. This is because they can inform the | |
86 | // inference of the impl's type parameters. | |
87 | let mut fulfill_cx = FulfillmentContext::new(); | |
f035d41b | 88 | let impl_source = selection.map(|predicate| { |
abe05a73 XL |
89 | debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); |
90 | fulfill_cx.register_predicate_obligation(&infcx, predicate); | |
91 | }); | |
fc512014 | 92 | let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source); |
abe05a73 | 93 | |
6a06907d | 94 | debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source); |
f035d41b | 95 | Ok(impl_source) |
abe05a73 XL |
96 | }) |
97 | } | |
cc61c64b | 98 | |
cc61c64b XL |
99 | // # Global Cache |
100 | ||
ba9703b0 XL |
101 | /// Finishes processes any obligations that remain in the |
102 | /// fulfillment context, and then returns the result with all type | |
103 | /// variables removed and regions erased. Because this is intended | |
104 | /// for use after type-check has completed, if any errors occur, | |
105 | /// it will panic. It is used during normalization and other cases | |
106 | /// where processing the obligations in `fulfill_cx` may cause | |
107 | /// type inference variables that appear in `result` to be | |
108 | /// unified, and hence we need to process those obligations to get | |
109 | /// the complete picture of the type. | |
110 | fn drain_fulfillment_cx_or_panic<T>( | |
111 | infcx: &InferCtxt<'_, 'tcx>, | |
112 | fulfill_cx: &mut FulfillmentContext<'tcx>, | |
fc512014 | 113 | result: T, |
ba9703b0 XL |
114 | ) -> T |
115 | where | |
116 | T: TypeFoldable<'tcx>, | |
117 | { | |
118 | debug!("drain_fulfillment_cx_or_panic()"); | |
0531ce1d | 119 | |
ba9703b0 XL |
120 | // In principle, we only need to do this so long as `result` |
121 | // contains unbound type parameters. It could be a slight | |
122 | // optimization to stop iterating early. | |
123 | if let Err(errors) = fulfill_cx.select_all_or_error(infcx) { | |
1b1a35ee XL |
124 | infcx.tcx.sess.delay_span_bug( |
125 | rustc_span::DUMMY_SP, | |
126 | &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors), | |
127 | ); | |
0531ce1d | 128 | } |
ba9703b0 XL |
129 | |
130 | let result = infcx.resolve_vars_if_possible(result); | |
fc512014 | 131 | infcx.tcx.erase_regions(result) |
0531ce1d | 132 | } |