]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_trait_selection/src/traits/codegen/mod.rs
New upstream version 1.48.0+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / 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, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
9 Unimplemented,
10 };
11 use rustc_errors::ErrorReported;
12 use rustc_middle::ty::fold::TypeFoldable;
13 use rustc_middle::ty::{self, TyCtxt};
14
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>(
22 ty: TyCtxt<'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);
27
28 debug!(
29 "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
30 (param_env, trait_ref),
31 trait_ref.def_id()
32 );
33
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);
38
39 let obligation_cause = ObligationCause::dummy();
40 let obligation =
41 Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
42
43 let selection = match selcx.select(&obligation) {
44 Ok(Some(selection)) => selection,
45 Ok(None) => {
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(
53 rustc_span::DUMMY_SP,
54 &format!(
55 "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
56 overflow or prior type error",
57 trait_ref
58 ),
59 );
60 return Err(ErrorReported);
61 }
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(
66 rustc_span::DUMMY_SP,
67 &format!(
68 "Encountered error `Unimplemented` selecting `{:?}` during codegen",
69 trait_ref
70 ),
71 );
72 return Err(ErrorReported);
73 }
74 Err(e) => {
75 bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
76 }
77 };
78
79 debug!("fulfill_obligation: selection={:?}", selection);
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();
85 let impl_source = selection.map(|predicate| {
86 debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
87 fulfill_cx.register_predicate_obligation(&infcx, predicate);
88 });
89 let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source);
90
91 info!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
92 Ok(impl_source)
93 })
94 }
95
96 // # Global Cache
97
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>,
110 result: &T,
111 ) -> T
112 where
113 T: TypeFoldable<'tcx>,
114 {
115 debug!("drain_fulfillment_cx_or_panic()");
116
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),
124 );
125 }
126
127 let result = infcx.resolve_vars_if_possible(result);
128 infcx.tcx.erase_regions(&result)
129 }