]>
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 | /// |
29967ef6 | 21 | /// This also expects that `trait_ref` is fully normalized. |
dc9dc135 | 22 | pub fn codegen_fulfill_obligation<'tcx>( |
29967ef6 | 23 | tcx: TyCtxt<'tcx>, |
dc9dc135 | 24 | (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), |
5099ac24 | 25 | ) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorReported> { |
abe05a73 | 26 | // Remove any references to regions; this helps improve caching. |
fc512014 | 27 | let trait_ref = tcx.erase_regions(trait_ref); |
29967ef6 XL |
28 | // We expect the input to be fully normalized. |
29 | debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref)); | |
dfeec247 XL |
30 | debug!( |
31 | "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", | |
32 | (param_env, trait_ref), | |
33 | trait_ref.def_id() | |
34 | ); | |
abe05a73 XL |
35 | |
36 | // Do the initial selection for the obligation. This yields the | |
37 | // shallow result we are looking for -- that is, what specific impl. | |
29967ef6 | 38 | tcx.infer_ctxt().enter(|infcx| { |
abe05a73 XL |
39 | let mut selcx = SelectionContext::new(&infcx); |
40 | ||
41 | let obligation_cause = ObligationCause::dummy(); | |
dfeec247 XL |
42 | let obligation = |
43 | Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); | |
abe05a73 XL |
44 | |
45 | let selection = match selcx.select(&obligation) { | |
46 | Ok(Some(selection)) => selection, | |
47 | Ok(None) => { | |
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. | |
74b04a01 XL |
54 | infcx.tcx.sess.delay_span_bug( |
55 | rustc_span::DUMMY_SP, | |
56 | &format!( | |
57 | "encountered ambiguity selecting `{:?}` during codegen, presuming due to \ | |
58 | overflow or prior type error", | |
59 | trait_ref | |
60 | ), | |
61 | ); | |
f9f354fc | 62 | return Err(ErrorReported); |
abe05a73 | 63 | } |
3dfed10e XL |
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. | |
5099ac24 FG |
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. | |
3dfed10e XL |
69 | infcx.tcx.sess.delay_span_bug( |
70 | rustc_span::DUMMY_SP, | |
71 | &format!( | |
72 | "Encountered error `Unimplemented` selecting `{:?}` during codegen", | |
73 | trait_ref | |
74 | ), | |
75 | ); | |
76 | return Err(ErrorReported); | |
77 | } | |
abe05a73 | 78 | Err(e) => { |
0bf4aa26 | 79 | bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) |
abe05a73 XL |
80 | } |
81 | }; | |
82 | ||
83 | debug!("fulfill_obligation: selection={:?}", selection); | |
84 | ||
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(); | |
f035d41b | 89 | let impl_source = selection.map(|predicate| { |
abe05a73 XL |
90 | debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); |
91 | fulfill_cx.register_predicate_obligation(&infcx, predicate); | |
92 | }); | |
fc512014 | 93 | let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source); |
abe05a73 | 94 | |
6a06907d | 95 | debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source); |
5099ac24 | 96 | Ok(&*tcx.arena.alloc(impl_source)) |
abe05a73 XL |
97 | }) |
98 | } | |
cc61c64b | 99 | |
cc61c64b XL |
100 | // # Global Cache |
101 | ||
ba9703b0 XL |
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 | |
5099ac24 | 105 | /// for use outside of type inference, if any errors occur, |
ba9703b0 XL |
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. | |
a2a8927a | 111 | fn drain_fulfillment_cx_or_panic<'tcx, T>( |
ba9703b0 XL |
112 | infcx: &InferCtxt<'_, 'tcx>, |
113 | fulfill_cx: &mut FulfillmentContext<'tcx>, | |
fc512014 | 114 | result: T, |
ba9703b0 XL |
115 | ) -> T |
116 | where | |
117 | T: TypeFoldable<'tcx>, | |
118 | { | |
119 | debug!("drain_fulfillment_cx_or_panic()"); | |
0531ce1d | 120 | |
ba9703b0 XL |
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. | |
3c0e092e XL |
124 | let errors = fulfill_cx.select_all_or_error(infcx); |
125 | if !errors.is_empty() { | |
1b1a35ee XL |
126 | infcx.tcx.sess.delay_span_bug( |
127 | rustc_span::DUMMY_SP, | |
5099ac24 FG |
128 | &format!( |
129 | "Encountered errors `{:?}` resolving bounds outside of type inference", | |
130 | errors | |
131 | ), | |
1b1a35ee | 132 | ); |
0531ce1d | 133 | } |
ba9703b0 XL |
134 | |
135 | let result = infcx.resolve_vars_if_possible(result); | |
fc512014 | 136 | infcx.tcx.erase_regions(result) |
0531ce1d | 137 | } |