]> git.proxmox.com Git - rustc.git/blob - src/librustc_trait_selection/traits/codegen/mod.rs
New upstream version 1.44.1+dfsg1
[rustc.git] / src / librustc_trait_selection / traits / codegen / mod.rs
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
4 // general routines.
5
6 use crate::infer::{InferCtxt, TyCtxtInferExt};
7 use crate::traits::{
8 FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable,
9 };
10 use rustc_middle::ty::fold::TypeFoldable;
11 use rustc_middle::ty::{self, TyCtxt};
12
13 /// Attempts to resolve an obligation to a vtable. The result is
14 /// a shallow vtable resolution, meaning that we do not
15 /// (necessarily) resolve all nested obligations on the impl. Note
16 /// that type check should guarantee to us that all nested
17 /// obligations *could be* resolved if we wanted to.
18 /// Assumes that this is run after the entire crate has been successfully type-checked.
19 pub fn codegen_fulfill_obligation<'tcx>(
20 ty: TyCtxt<'tcx>,
21 (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
22 ) -> Option<Vtable<'tcx, ()>> {
23 // Remove any references to regions; this helps improve caching.
24 let trait_ref = ty.erase_regions(&trait_ref);
25
26 debug!(
27 "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
28 (param_env, trait_ref),
29 trait_ref.def_id()
30 );
31
32 // Do the initial selection for the obligation. This yields the
33 // shallow result we are looking for -- that is, what specific impl.
34 ty.infer_ctxt().enter(|infcx| {
35 let mut selcx = SelectionContext::new(&infcx);
36
37 let obligation_cause = ObligationCause::dummy();
38 let obligation =
39 Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
40
41 let selection = match selcx.select(&obligation) {
42 Ok(Some(selection)) => selection,
43 Ok(None) => {
44 // Ambiguity can happen when monomorphizing during trans
45 // expands to some humongo type that never occurred
46 // statically -- this humongo type can then overflow,
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.
50 infcx.tcx.sess.delay_span_bug(
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 );
58 return None;
59 }
60 Err(e) => {
61 bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
62 }
63 };
64
65 debug!("fulfill_obligation: selection={:?}", selection);
66
67 // Currently, we use a fulfillment context to completely resolve
68 // all nested obligations. This is because they can inform the
69 // inference of the impl's type parameters.
70 let mut fulfill_cx = FulfillmentContext::new();
71 let vtable = selection.map(|predicate| {
72 debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
73 fulfill_cx.register_predicate_obligation(&infcx, predicate);
74 });
75 let vtable = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &vtable);
76
77 info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
78 Some(vtable)
79 })
80 }
81
82 // # Global Cache
83
84 /// Finishes processes any obligations that remain in the
85 /// fulfillment context, and then returns the result with all type
86 /// variables removed and regions erased. Because this is intended
87 /// for use after type-check has completed, if any errors occur,
88 /// it will panic. It is used during normalization and other cases
89 /// where processing the obligations in `fulfill_cx` may cause
90 /// type inference variables that appear in `result` to be
91 /// unified, and hence we need to process those obligations to get
92 /// the complete picture of the type.
93 fn drain_fulfillment_cx_or_panic<T>(
94 infcx: &InferCtxt<'_, 'tcx>,
95 fulfill_cx: &mut FulfillmentContext<'tcx>,
96 result: &T,
97 ) -> T
98 where
99 T: TypeFoldable<'tcx>,
100 {
101 debug!("drain_fulfillment_cx_or_panic()");
102
103 // In principle, we only need to do this so long as `result`
104 // contains unbound type parameters. It could be a slight
105 // optimization to stop iterating early.
106 if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
107 bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
108 }
109
110 let result = infcx.resolve_vars_if_possible(result);
111 infcx.tcx.erase_regions(&result)
112 }