]>
Commit | Line | Data |
---|---|---|
29967ef6 | 1 | mod _impl; |
9ffffee4 | 2 | mod adjust_fulfillment_errors; |
923072b8 | 3 | mod arg_matrix; |
29967ef6 XL |
4 | mod checks; |
5 | mod suggestions; | |
6 | ||
7 | pub use _impl::*; | |
487cf647 | 8 | use rustc_errors::ErrorGuaranteed; |
29967ef6 XL |
9 | pub use suggestions::*; |
10 | ||
2b03887a | 11 | use crate::coercion::DynamicCoerceMany; |
487cf647 | 12 | use crate::{Diverges, EnclosingBreakables, Inherited}; |
29967ef6 | 13 | use rustc_hir as hir; |
9ffffee4 | 14 | use rustc_hir::def_id::{DefId, LocalDefId}; |
2b03887a | 15 | use rustc_hir_analysis::astconv::AstConv; |
29967ef6 | 16 | use rustc_infer::infer; |
2b03887a | 17 | use rustc_infer::infer::error_reporting::TypeErrCtxt; |
29967ef6 | 18 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; |
5e7ed085 | 19 | use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; |
29967ef6 | 20 | use rustc_middle::ty::subst::GenericArgKind; |
9ffffee4 | 21 | use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; |
29967ef6 | 22 | use rustc_session::Session; |
6a06907d | 23 | use rustc_span::symbol::Ident; |
9c376795 | 24 | use rustc_span::{self, Span, DUMMY_SP}; |
487cf647 | 25 | use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; |
29967ef6 XL |
26 | |
27 | use std::cell::{Cell, RefCell}; | |
28 | use std::ops::Deref; | |
29 | ||
f2b60f7d FG |
30 | /// The `FnCtxt` stores type-checking context needed to type-check bodies of |
31 | /// functions, closures, and `const`s, including performing type inference | |
32 | /// with [`InferCtxt`]. | |
33 | /// | |
34 | /// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures* | |
35 | /// and thus does not perform type inference. | |
36 | /// | |
37 | /// See [`ItemCtxt`]'s docs for more. | |
38 | /// | |
2b03887a | 39 | /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt |
f2b60f7d | 40 | /// [`InferCtxt`]: infer::InferCtxt |
29967ef6 | 41 | pub struct FnCtxt<'a, 'tcx> { |
9ffffee4 | 42 | pub(super) body_id: LocalDefId, |
29967ef6 XL |
43 | |
44 | /// The parameter environment used for proving trait obligations | |
45 | /// in this function. This can change when we descend into | |
46 | /// closures (as they bring new things into scope), hence it is | |
47 | /// not part of `Inherited` (as of the time of this writing, | |
48 | /// closures do not yet change the environment, but they will | |
49 | /// eventually). | |
50 | pub(super) param_env: ty::ParamEnv<'tcx>, | |
51 | ||
52 | /// Number of errors that had been reported when we started | |
53 | /// checking this function. On exit, if we find that *more* errors | |
54 | /// have been reported, we will skip regionck and other work that | |
55 | /// expects the types within the function to be consistent. | |
56 | // FIXME(matthewjasper) This should not exist, and it's not correct | |
57 | // if type checking is run in parallel. | |
58 | err_count_on_creation: usize, | |
59 | ||
60 | /// If `Some`, this stores coercion information for returned | |
61 | /// expressions. If `None`, this is in a context where return is | |
62 | /// inappropriate, such as a const expression. | |
63 | /// | |
64 | /// This is a `RefCell<DynamicCoerceMany>`, which means that we | |
65 | /// can track all the return expressions and then use them to | |
66 | /// compute a useful coercion from the set, similar to a match | |
67 | /// expression or other branching context. You can use methods | |
68 | /// like `expected_ty` to access the declared return type (if | |
69 | /// any). | |
70 | pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>, | |
71 | ||
29967ef6 | 72 | /// First span of a return site that we find. Used in error messages. |
5869c6ff | 73 | pub(super) ret_coercion_span: Cell<Option<Span>>, |
29967ef6 XL |
74 | |
75 | pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, | |
76 | ||
29967ef6 XL |
77 | /// Whether the last checked node generates a divergence (e.g., |
78 | /// `return` will set this to `Always`). In general, when entering | |
79 | /// an expression or other node in the tree, the initial value | |
80 | /// indicates whether prior parts of the containing expression may | |
81 | /// have diverged. It is then typically set to `Maybe` (and the | |
82 | /// old value remembered) for processing the subparts of the | |
83 | /// current expression. As each subpart is processed, they may set | |
84 | /// the flag to `Always`, etc. Finally, at the end, we take the | |
85 | /// result and "union" it with the original value, so that when we | |
86 | /// return the flag indicates if any subpart of the parent | |
87 | /// expression (up to and including this part) has diverged. So, | |
88 | /// if you read it after evaluating a subexpression `X`, the value | |
89 | /// you get indicates whether any subexpression that was | |
90 | /// evaluating up to and including `X` diverged. | |
91 | /// | |
92 | /// We currently use this flag only for diagnostic purposes: | |
93 | /// | |
94 | /// - To warn about unreachable code: if, after processing a | |
95 | /// sub-expression but before we have applied the effects of the | |
96 | /// current node, we see that the flag is set to `Always`, we | |
97 | /// can issue a warning. This corresponds to something like | |
98 | /// `foo(return)`; we warn on the `foo()` expression. (We then | |
99 | /// update the flag to `WarnedAlways` to suppress duplicate | |
100 | /// reports.) Similarly, if we traverse to a fresh statement (or | |
94222f64 | 101 | /// tail expression) from an `Always` setting, we will issue a |
29967ef6 XL |
102 | /// warning. This corresponds to something like `{return; |
103 | /// foo();}` or `{return; 22}`, where we would warn on the | |
104 | /// `foo()` or `22`. | |
105 | /// | |
106 | /// An expression represents dead code if, after checking it, | |
107 | /// the diverges flag is set to something other than `Maybe`. | |
108 | pub(super) diverges: Cell<Diverges>, | |
109 | ||
29967ef6 XL |
110 | pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>, |
111 | ||
2b03887a | 112 | pub(super) inh: &'a Inherited<'tcx>, |
94222f64 | 113 | |
487cf647 | 114 | pub(super) fallback_has_occurred: Cell<bool>, |
29967ef6 XL |
115 | } |
116 | ||
117 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
118 | pub fn new( | |
2b03887a | 119 | inh: &'a Inherited<'tcx>, |
29967ef6 | 120 | param_env: ty::ParamEnv<'tcx>, |
9ffffee4 | 121 | body_id: LocalDefId, |
29967ef6 XL |
122 | ) -> FnCtxt<'a, 'tcx> { |
123 | FnCtxt { | |
124 | body_id, | |
125 | param_env, | |
126 | err_count_on_creation: inh.tcx.sess.err_count(), | |
127 | ret_coercion: None, | |
5869c6ff | 128 | ret_coercion_span: Cell::new(None), |
29967ef6 | 129 | resume_yield_tys: None, |
29967ef6 | 130 | diverges: Cell::new(Diverges::Maybe), |
29967ef6 XL |
131 | enclosing_breakables: RefCell::new(EnclosingBreakables { |
132 | stack: Vec::new(), | |
133 | by_id: Default::default(), | |
134 | }), | |
135 | inh, | |
487cf647 | 136 | fallback_has_occurred: Cell::new(false), |
29967ef6 XL |
137 | } |
138 | } | |
139 | ||
140 | pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { | |
141 | ObligationCause::new(span, self.body_id, code) | |
142 | } | |
143 | ||
144 | pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { | |
145 | self.cause(span, ObligationCauseCode::MiscObligation) | |
146 | } | |
147 | ||
148 | pub fn sess(&self) -> &Session { | |
149 | &self.tcx.sess | |
150 | } | |
151 | ||
2b03887a FG |
152 | /// Creates an `TypeErrCtxt` with a reference to the in-progress |
153 | /// `TypeckResults` which is used for diagnostics. | |
154 | /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`. | |
155 | /// | |
156 | /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt | |
157 | pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> { | |
487cf647 FG |
158 | TypeErrCtxt { |
159 | infcx: &self.infcx, | |
160 | typeck_results: Some(self.typeck_results.borrow()), | |
161 | fallback_has_occurred: self.fallback_has_occurred.get(), | |
162 | normalize_fn_sig: Box::new(|fn_sig| { | |
163 | if fn_sig.has_escaping_bound_vars() { | |
164 | return fn_sig; | |
165 | } | |
166 | self.probe(|_| { | |
167 | let ocx = ObligationCtxt::new_in_snapshot(self); | |
168 | let normalized_fn_sig = | |
169 | ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig); | |
170 | if ocx.select_all_or_error().is_empty() { | |
171 | let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig); | |
172 | if !normalized_fn_sig.needs_infer() { | |
173 | return normalized_fn_sig; | |
174 | } | |
175 | } | |
176 | fn_sig | |
177 | }) | |
178 | }), | |
9c376795 FG |
179 | autoderef_steps: Box::new(|ty| { |
180 | let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors(); | |
181 | let mut steps = vec![]; | |
182 | while let Some((ty, _)) = autoderef.next() { | |
183 | steps.push((ty, autoderef.current_obligations())); | |
184 | } | |
185 | steps | |
186 | }), | |
487cf647 | 187 | } |
2b03887a FG |
188 | } |
189 | ||
29967ef6 XL |
190 | pub fn errors_reported_since_creation(&self) -> bool { |
191 | self.tcx.sess.err_count() > self.err_count_on_creation | |
192 | } | |
193 | } | |
194 | ||
195 | impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { | |
2b03887a | 196 | type Target = Inherited<'tcx>; |
29967ef6 XL |
197 | fn deref(&self) -> &Self::Target { |
198 | &self.inh | |
199 | } | |
200 | } | |
201 | ||
202 | impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { | |
203 | fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { | |
204 | self.tcx | |
205 | } | |
206 | ||
487cf647 | 207 | fn item_def_id(&self) -> DefId { |
9ffffee4 | 208 | self.body_id.to_def_id() |
29967ef6 XL |
209 | } |
210 | ||
6a06907d XL |
211 | fn get_type_parameter_bounds( |
212 | &self, | |
213 | _: Span, | |
353b0b11 | 214 | def_id: LocalDefId, |
6a06907d XL |
215 | _: Ident, |
216 | ) -> ty::GenericPredicates<'tcx> { | |
29967ef6 | 217 | let tcx = self.tcx; |
353b0b11 | 218 | let item_def_id = tcx.hir().ty_param_owner(def_id); |
29967ef6 | 219 | let generics = tcx.generics_of(item_def_id); |
353b0b11 | 220 | let index = generics.param_def_id_to_index[&def_id.to_def_id()]; |
29967ef6 XL |
221 | ty::GenericPredicates { |
222 | parent: None, | |
223 | predicates: tcx.arena.alloc_from_iter( | |
224 | self.param_env.caller_bounds().iter().filter_map(|predicate| { | |
5869c6ff | 225 | match predicate.kind().skip_binder() { |
487cf647 FG |
226 | ty::PredicateKind::Clause(ty::Clause::Trait(data)) |
227 | if data.self_ty().is_param(index) => | |
228 | { | |
29967ef6 XL |
229 | // HACK(eddyb) should get the original `Span`. |
230 | let span = tcx.def_span(def_id); | |
231 | Some((predicate, span)) | |
232 | } | |
233 | _ => None, | |
234 | } | |
235 | }), | |
236 | ), | |
237 | } | |
238 | } | |
239 | ||
240 | fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> { | |
241 | let v = match def { | |
242 | Some(def) => infer::EarlyBoundRegion(span, def.name), | |
243 | None => infer::MiscVariable(span), | |
244 | }; | |
245 | Some(self.next_region_var(v)) | |
246 | } | |
247 | ||
248 | fn allow_ty_infer(&self) -> bool { | |
249 | true | |
250 | } | |
251 | ||
252 | fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { | |
253 | if let Some(param) = param { | |
254 | if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { | |
255 | return ty; | |
256 | } | |
257 | unreachable!() | |
258 | } else { | |
259 | self.next_ty_var(TypeVariableOrigin { | |
260 | kind: TypeVariableOriginKind::TypeInference, | |
261 | span, | |
262 | }) | |
263 | } | |
264 | } | |
265 | ||
266 | fn ct_infer( | |
267 | &self, | |
268 | ty: Ty<'tcx>, | |
269 | param: Option<&ty::GenericParamDef>, | |
270 | span: Span, | |
5099ac24 | 271 | ) -> Const<'tcx> { |
29967ef6 XL |
272 | if let Some(param) = param { |
273 | if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { | |
274 | return ct; | |
275 | } | |
276 | unreachable!() | |
277 | } else { | |
278 | self.next_const_var( | |
279 | ty, | |
280 | ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, | |
281 | ) | |
282 | } | |
283 | } | |
284 | ||
285 | fn projected_ty_from_poly_trait_ref( | |
286 | &self, | |
287 | span: Span, | |
288 | item_def_id: DefId, | |
289 | item_segment: &hir::PathSegment<'_>, | |
290 | poly_trait_ref: ty::PolyTraitRef<'tcx>, | |
291 | ) -> Ty<'tcx> { | |
9ffffee4 | 292 | let trait_ref = self.instantiate_binder_with_fresh_vars( |
29967ef6 XL |
293 | span, |
294 | infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), | |
fc512014 | 295 | poly_trait_ref, |
29967ef6 XL |
296 | ); |
297 | ||
9c376795 | 298 | let item_substs = self.astconv().create_substs_for_associated_item( |
29967ef6 XL |
299 | span, |
300 | item_def_id, | |
301 | item_segment, | |
302 | trait_ref.substs, | |
303 | ); | |
304 | ||
305 | self.tcx().mk_projection(item_def_id, item_substs) | |
306 | } | |
307 | ||
9c376795 FG |
308 | fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> { |
309 | match ty.kind() { | |
310 | ty::Adt(adt_def, _) => Some(*adt_def), | |
311 | // FIXME(#104767): Should we handle bound regions here? | |
312 | ty::Alias(ty::Projection, _) if !ty.has_escaping_bound_vars() => { | |
313 | self.normalize(span, ty).ty_adt_def() | |
314 | } | |
315 | _ => None, | |
29967ef6 XL |
316 | } |
317 | } | |
318 | ||
487cf647 FG |
319 | fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { |
320 | self.infcx.set_tainted_by_errors(e) | |
29967ef6 XL |
321 | } |
322 | ||
9c376795 FG |
323 | fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) { |
324 | // FIXME: normalization and escaping regions | |
325 | let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty }; | |
29967ef6 XL |
326 | self.write_ty(hir_id, ty) |
327 | } | |
9ffffee4 FG |
328 | |
329 | fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> { | |
330 | Some(&self.infcx) | |
331 | } | |
29967ef6 | 332 | } |
9c376795 FG |
333 | |
334 | /// Represents a user-provided type in the raw form (never normalized). | |
335 | /// | |
336 | /// This is a bridge between the interface of `AstConv`, which outputs a raw `Ty`, | |
337 | /// and the API in this module, which expect `Ty` to be fully normalized. | |
338 | #[derive(Clone, Copy, Debug)] | |
339 | pub struct RawTy<'tcx> { | |
340 | pub raw: Ty<'tcx>, | |
341 | ||
342 | /// The normalized form of `raw`, stored here for efficiency. | |
343 | pub normalized: Ty<'tcx>, | |
344 | } |