]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/traits/codegen.rs
Auto merge of #95993 - jyn514:fix-stage0-doctests, r=Mark-Simulacrum
[rust.git] / compiler / rustc_trait_selection / src / traits / codegen.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::ErrorGuaranteed;
12 use rustc_middle::ty::fold::TypeFoldable;
13 use rustc_middle::ty::{self, TyCtxt};
14
15 /// Attempts to resolve an obligation to an `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 ///
21 /// This also expects that `trait_ref` is fully normalized.
22 #[instrument(level = "debug", skip(tcx))]
23 pub fn codegen_fulfill_obligation<'tcx>(
24     tcx: TyCtxt<'tcx>,
25     (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
26 ) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> {
27     // Remove any references to regions; this helps improve caching.
28     let trait_ref = tcx.erase_regions(trait_ref);
29     // We expect the input to be fully normalized.
30     debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
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     tcx.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 humongous type that never occurred
46                 // statically -- this humongous 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                 let reported = 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 Err(reported);
59             }
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.
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.
65                 let guar = 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(guar);
73             }
74             Err(e) => {
75                 bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
76             }
77         };
78
79         debug!(?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             fulfill_cx.register_predicate_obligation(&infcx, predicate);
87         });
88         let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
89
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:?}");
95         Ok(&*tcx.arena.alloc(impl_source))
96     })
97 }
98
99 // # Global Cache
100
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 outside of type inference, 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<'tcx, T>(
111     infcx: &InferCtxt<'_, 'tcx>,
112     fulfill_cx: &mut FulfillmentContext<'tcx>,
113     result: T,
114 ) -> T
115 where
116     T: TypeFoldable<'tcx>,
117 {
118     debug!("drain_fulfillment_cx_or_panic()");
119
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     let errors = fulfill_cx.select_all_or_error(infcx);
124     if !errors.is_empty() {
125         infcx.tcx.sess.delay_span_bug(
126             rustc_span::DUMMY_SP,
127             &format!(
128                 "Encountered errors `{:?}` resolving bounds outside of type inference",
129                 errors
130             ),
131         );
132     }
133
134     let result = infcx.resolve_vars_if_possible(result);
135     infcx.tcx.erase_regions(result)
136 }