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