]>
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 | }; |
5e7ed085 | 11 | use rustc_errors::ErrorGuaranteed; |
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. |
5e7ed085 | 22 | #[instrument(level = "debug", skip(tcx))] |
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>), |
5e7ed085 | 26 | ) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> { |
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)); | |
abe05a73 XL |
31 | |
32 | // Do the initial selection for the obligation. This yields the | |
33 | // shallow result we are looking for -- that is, what specific impl. | |
29967ef6 | 34 | tcx.infer_ctxt().enter(|infcx| { |
abe05a73 XL |
35 | let mut selcx = SelectionContext::new(&infcx); |
36 | ||
37 | let obligation_cause = ObligationCause::dummy(); | |
dfeec247 XL |
38 | let obligation = |
39 | Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); | |
abe05a73 XL |
40 | |
41 | let selection = match selcx.select(&obligation) { | |
42 | Ok(Some(selection)) => selection, | |
43 | Ok(None) => { | |
44 | // Ambiguity can happen when monomorphizing during trans | |
5e7ed085 FG |
45 | // expands to some humongous type that never occurred |
46 | // statically -- this humongous type can then overflow, | |
abe05a73 XL |
47 | // leading to an ambiguous result. So report this as an |
48 | // overflow bug, since I believe this is the only case | |
49 | // where ambiguity can result. | |
5e7ed085 | 50 | let reported = infcx.tcx.sess.delay_span_bug( |
74b04a01 XL |
51 | rustc_span::DUMMY_SP, |
52 | &format!( | |
53 | "encountered ambiguity selecting `{:?}` during codegen, presuming due to \ | |
54 | overflow or prior type error", | |
55 | trait_ref | |
56 | ), | |
57 | ); | |
5e7ed085 | 58 | return Err(reported); |
abe05a73 | 59 | } |
3dfed10e XL |
60 | Err(Unimplemented) => { |
61 | // This can trigger when we probe for the source of a `'static` lifetime requirement | |
62 | // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound. | |
5099ac24 FG |
63 | // This can also trigger when we have a global bound that is not actually satisfied, |
64 | // but was included during typeck due to the trivial_bounds feature. | |
5e7ed085 | 65 | let guar = infcx.tcx.sess.delay_span_bug( |
3dfed10e XL |
66 | rustc_span::DUMMY_SP, |
67 | &format!( | |
68 | "Encountered error `Unimplemented` selecting `{:?}` during codegen", | |
69 | trait_ref | |
70 | ), | |
71 | ); | |
5e7ed085 | 72 | return Err(guar); |
3dfed10e | 73 | } |
abe05a73 | 74 | Err(e) => { |
0bf4aa26 | 75 | bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) |
abe05a73 XL |
76 | } |
77 | }; | |
78 | ||
5e7ed085 | 79 | debug!(?selection); |
abe05a73 XL |
80 | |
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(); | |
f035d41b | 85 | let impl_source = selection.map(|predicate| { |
abe05a73 XL |
86 | fulfill_cx.register_predicate_obligation(&infcx, predicate); |
87 | }); | |
fc512014 | 88 | let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source); |
abe05a73 | 89 | |
5e7ed085 FG |
90 | // Opaque types may have gotten their hidden types constrained, but we can ignore them safely |
91 | // as they will get constrained elsewhere, too. | |
92 | let _opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); | |
93 | ||
94 | debug!("Cache miss: {trait_ref:?} => {impl_source:?}"); | |
5099ac24 | 95 | Ok(&*tcx.arena.alloc(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 | |
5099ac24 | 104 | /// for use outside of type inference, if any errors occur, |
ba9703b0 XL |
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. | |
a2a8927a | 110 | fn drain_fulfillment_cx_or_panic<'tcx, T>( |
ba9703b0 XL |
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. | |
3c0e092e XL |
123 | let errors = fulfill_cx.select_all_or_error(infcx); |
124 | if !errors.is_empty() { | |
1b1a35ee XL |
125 | infcx.tcx.sess.delay_span_bug( |
126 | rustc_span::DUMMY_SP, | |
5099ac24 FG |
127 | &format!( |
128 | "Encountered errors `{:?}` resolving bounds outside of type inference", | |
129 | errors | |
130 | ), | |
1b1a35ee | 131 | ); |
0531ce1d | 132 | } |
ba9703b0 XL |
133 | |
134 | let result = infcx.resolve_vars_if_possible(result); | |
fc512014 | 135 | infcx.tcx.erase_regions(result) |
0531ce1d | 136 | } |