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