]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/check/inherited.rs
New upstream version 1.65.0+dfsg1
[rustc.git] / compiler / rustc_typeck / src / check / inherited.rs
CommitLineData
1b1a35ee 1use super::callee::DeferredCallResolution;
1b1a35ee 2
c295e0f8 3use rustc_data_structures::fx::FxHashSet;
f2b60f7d 4use rustc_data_structures::sync::Lrc;
1b1a35ee 5use rustc_hir as hir;
064997fb 6use rustc_hir::def_id::LocalDefId;
1b1a35ee
XL
7use rustc_hir::HirIdMap;
8use rustc_infer::infer;
9use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
10use rustc_middle::ty::fold::TypeFoldable;
064997fb 11use rustc_middle::ty::visit::TypeVisitable;
94222f64 12use rustc_middle::ty::{self, Ty, TyCtxt};
064997fb 13use rustc_span::def_id::LocalDefIdMap;
1b1a35ee
XL
14use rustc_span::{self, Span};
15use rustc_trait_selection::infer::InferCtxtExt as _;
f2b60f7d
FG
16use rustc_trait_selection::traits::{
17 self, ObligationCause, ObligationCtxt, TraitEngine, TraitEngineExt as _,
18};
1b1a35ee
XL
19
20use std::cell::RefCell;
21use std::ops::Deref;
22
23/// Closures defined within the function. For example:
04454e1e
FG
24/// ```ignore (illustrative)
25/// fn foo() {
26/// bar(move|| { ... })
27/// }
28/// ```
1b1a35ee
XL
29/// Here, the function `foo()` and the closure passed to
30/// `bar()` will each have their own `FnCtxt`, but they will
31/// share the inherited fields.
32pub struct Inherited<'a, 'tcx> {
33 pub(super) infcx: InferCtxt<'a, 'tcx>,
34
064997fb 35 pub(super) typeck_results: &'a RefCell<ty::TypeckResults<'tcx>>,
1b1a35ee
XL
36
37 pub(super) locals: RefCell<HirIdMap<super::LocalTy<'tcx>>>,
38
39 pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
40
41 // Some additional `Sized` obligations badly affect type inference.
42 // These obligations are added in a later stage of typeck.
f2b60f7d 43 // Removing these may also cause additional complications, see #101066.
1b1a35ee
XL
44 pub(super) deferred_sized_obligations:
45 RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>,
46
47 // When we process a call like `c()` where `c` is a closure type,
48 // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
49 // `FnOnce` closure. In that case, we defer full resolution of the
50 // call until upvar inference can kick in and make the
51 // decision. We keep these deferred resolutions grouped by the
52 // def-id of the closure, so that once we decide, we can easily go
53 // back and process them.
064997fb 54 pub(super) deferred_call_resolutions: RefCell<LocalDefIdMap<Vec<DeferredCallResolution<'tcx>>>>,
1b1a35ee
XL
55
56 pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>,
57
923072b8
FG
58 pub(super) deferred_transmute_checks: RefCell<Vec<(Ty<'tcx>, Ty<'tcx>, Span)>>,
59
60 pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>,
61
1b1a35ee
XL
62 pub(super) deferred_generator_interiors:
63 RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
64
1b1a35ee 65 pub(super) body_id: Option<hir::BodyId>,
c295e0f8
XL
66
67 /// Whenever we introduce an adjustment from `!` into a type variable,
68 /// we record that type variable here. This is later used to inform
69 /// fallback. See the `fallback` module for details.
70 pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
1b1a35ee
XL
71}
72
73impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
74 type Target = InferCtxt<'a, 'tcx>;
75 fn deref(&self) -> &Self::Target {
76 &self.infcx
77 }
78}
79
5e7ed085
FG
80/// A temporary returned by `Inherited::build(...)`. This is necessary
81/// for multiple `InferCtxt` to share the same `in_progress_typeck_results`
82/// without using `Rc` or something similar.
1b1a35ee
XL
83pub struct InheritedBuilder<'tcx> {
84 infcx: infer::InferCtxtBuilder<'tcx>,
85 def_id: LocalDefId,
86}
87
a2a8927a 88impl<'tcx> Inherited<'_, 'tcx> {
1b1a35ee
XL
89 pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
90 let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
91
92 InheritedBuilder {
064997fb
FG
93 infcx: tcx
94 .infer_ctxt()
95 .ignoring_regions()
f2b60f7d
FG
96 .with_fresh_in_progress_typeck_results(hir_owner)
97 .with_normalize_fn_sig_for_diagnostic(Lrc::new(move |infcx, fn_sig| {
98 if fn_sig.has_escaping_bound_vars() {
99 return fn_sig;
100 }
101 infcx.probe(|_| {
102 let ocx = ObligationCtxt::new_in_snapshot(infcx);
103 let normalized_fn_sig = ocx.normalize(
104 ObligationCause::dummy(),
105 // FIXME(compiler-errors): This is probably not the right param-env...
106 infcx.tcx.param_env(def_id),
107 fn_sig,
108 );
109 if ocx.select_all_or_error().is_empty() {
110 let normalized_fn_sig =
111 infcx.resolve_vars_if_possible(normalized_fn_sig);
112 if !normalized_fn_sig.needs_infer() {
113 return normalized_fn_sig;
114 }
115 }
116 fn_sig
117 })
118 })),
1b1a35ee
XL
119 def_id,
120 }
121 }
122}
123
124impl<'tcx> InheritedBuilder<'tcx> {
125 pub fn enter<F, R>(&mut self, f: F) -> R
126 where
127 F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R,
128 {
129 let def_id = self.def_id;
130 self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
131 }
132}
133
a2a8927a 134impl<'a, 'tcx> Inherited<'a, 'tcx> {
064997fb 135 fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
1b1a35ee 136 let tcx = infcx.tcx;
064997fb
FG
137 let body_id = tcx.hir().maybe_body_owned_by(def_id);
138 let typeck_results =
139 infcx.in_progress_typeck_results.expect("building `FnCtxt` without typeck results");
1b1a35ee
XL
140
141 Inherited {
064997fb 142 typeck_results,
1b1a35ee 143 infcx,
6a06907d 144 fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
1b1a35ee
XL
145 locals: RefCell::new(Default::default()),
146 deferred_sized_obligations: RefCell::new(Vec::new()),
147 deferred_call_resolutions: RefCell::new(Default::default()),
148 deferred_cast_checks: RefCell::new(Vec::new()),
923072b8
FG
149 deferred_transmute_checks: RefCell::new(Vec::new()),
150 deferred_asm_checks: RefCell::new(Vec::new()),
1b1a35ee 151 deferred_generator_interiors: RefCell::new(Vec::new()),
c295e0f8 152 diverging_type_vars: RefCell::new(Default::default()),
1b1a35ee
XL
153 body_id,
154 }
155 }
156
5e7ed085 157 #[instrument(level = "debug", skip(self))]
1b1a35ee 158 pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
1b1a35ee
XL
159 if obligation.has_escaping_bound_vars() {
160 span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
161 }
162 self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation);
163 }
164
165 pub(super) fn register_predicates<I>(&self, obligations: I)
166 where
167 I: IntoIterator<Item = traits::PredicateObligation<'tcx>>,
168 {
169 for obligation in obligations {
170 self.register_predicate(obligation);
171 }
172 }
173
174 pub(super) fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
175 self.register_predicates(infer_ok.obligations);
176 infer_ok.value
177 }
178
179 pub(super) fn normalize_associated_types_in<T>(
180 &self,
181 span: Span,
182 body_id: hir::HirId,
183 param_env: ty::ParamEnv<'tcx>,
fc512014 184 value: T,
1b1a35ee
XL
185 ) -> T
186 where
187 T: TypeFoldable<'tcx>,
188 {
136023e0
XL
189 self.normalize_associated_types_in_with_cause(
190 ObligationCause::misc(span, body_id),
191 param_env,
192 value,
193 )
194 }
195
196 pub(super) fn normalize_associated_types_in_with_cause<T>(
197 &self,
198 cause: ObligationCause<'tcx>,
199 param_env: ty::ParamEnv<'tcx>,
200 value: T,
201 ) -> T
202 where
203 T: TypeFoldable<'tcx>,
204 {
205 let ok = self.partially_normalize_associated_types_in(cause, param_env, value);
206 debug!(?ok);
1b1a35ee
XL
207 self.register_infer_ok_obligations(ok)
208 }
209}