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