]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
Auto merge of #105363 - WaffleLapkin:thin2win_box_next_argument, r=nnethercote
[rust.git] / compiler / rustc_hir_typeck / src / fn_ctxt / mod.rs
1 mod _impl;
2 mod arg_matrix;
3 mod checks;
4 mod suggestions;
5
6 pub use _impl::*;
7 use rustc_errors::ErrorGuaranteed;
8 pub use suggestions::*;
9
10 use crate::coercion::DynamicCoerceMany;
11 use crate::{Diverges, EnclosingBreakables, Inherited};
12 use rustc_hir as hir;
13 use rustc_hir::def_id::DefId;
14 use rustc_hir_analysis::astconv::AstConv;
15 use rustc_infer::infer;
16 use rustc_infer::infer::error_reporting::TypeErrCtxt;
17 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
18 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
19 use rustc_middle::ty::subst::GenericArgKind;
20 use rustc_middle::ty::visit::TypeVisitable;
21 use rustc_middle::ty::{self, Const, Ty, TyCtxt};
22 use rustc_session::Session;
23 use rustc_span::symbol::Ident;
24 use rustc_span::{self, Span};
25 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
26
27 use std::cell::{Cell, RefCell};
28 use std::ops::Deref;
29
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 ///
39 /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
40 /// [`InferCtxt`]: infer::InferCtxt
41 pub struct FnCtxt<'a, 'tcx> {
42     pub(super) body_id: hir::HirId,
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
72     /// First span of a return site that we find. Used in error messages.
73     pub(super) ret_coercion_span: Cell<Option<Span>>,
74
75     pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
76
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
101     ///   tail expression) from an `Always` setting, we will issue a
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
110     pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
111
112     pub(super) inh: &'a Inherited<'tcx>,
113
114     pub(super) fallback_has_occurred: Cell<bool>,
115 }
116
117 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
118     pub fn new(
119         inh: &'a Inherited<'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_span: Cell::new(None),
129             resume_yield_tys: None,
130             diverges: Cell::new(Diverges::Maybe),
131             enclosing_breakables: RefCell::new(EnclosingBreakables {
132                 stack: Vec::new(),
133                 by_id: Default::default(),
134             }),
135             inh,
136             fallback_has_occurred: Cell::new(false),
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
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> {
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             }),
179         }
180     }
181
182     pub fn errors_reported_since_creation(&self) -> bool {
183         self.tcx.sess.err_count() > self.err_count_on_creation
184     }
185 }
186
187 impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
188     type Target = Inherited<'tcx>;
189     fn deref(&self) -> &Self::Target {
190         &self.inh
191     }
192 }
193
194 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
195     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
196         self.tcx
197     }
198
199     fn item_def_id(&self) -> DefId {
200         self.body_id.owner.to_def_id()
201     }
202
203     fn get_type_parameter_bounds(
204         &self,
205         _: Span,
206         def_id: DefId,
207         _: Ident,
208     ) -> ty::GenericPredicates<'tcx> {
209         let tcx = self.tcx;
210         let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
211         let generics = tcx.generics_of(item_def_id);
212         let index = generics.param_def_id_to_index[&def_id];
213         ty::GenericPredicates {
214             parent: None,
215             predicates: tcx.arena.alloc_from_iter(
216                 self.param_env.caller_bounds().iter().filter_map(|predicate| {
217                     match predicate.kind().skip_binder() {
218                         ty::PredicateKind::Clause(ty::Clause::Trait(data))
219                             if data.self_ty().is_param(index) =>
220                         {
221                             // HACK(eddyb) should get the original `Span`.
222                             let span = tcx.def_span(def_id);
223                             Some((predicate, span))
224                         }
225                         _ => None,
226                     }
227                 }),
228             ),
229         }
230     }
231
232     fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
233         let v = match def {
234             Some(def) => infer::EarlyBoundRegion(span, def.name),
235             None => infer::MiscVariable(span),
236         };
237         Some(self.next_region_var(v))
238     }
239
240     fn allow_ty_infer(&self) -> bool {
241         true
242     }
243
244     fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
245         if let Some(param) = param {
246             if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
247                 return ty;
248             }
249             unreachable!()
250         } else {
251             self.next_ty_var(TypeVariableOrigin {
252                 kind: TypeVariableOriginKind::TypeInference,
253                 span,
254             })
255         }
256     }
257
258     fn ct_infer(
259         &self,
260         ty: Ty<'tcx>,
261         param: Option<&ty::GenericParamDef>,
262         span: Span,
263     ) -> Const<'tcx> {
264         if let Some(param) = param {
265             if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
266                 return ct;
267             }
268             unreachable!()
269         } else {
270             self.next_const_var(
271                 ty,
272                 ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
273             )
274         }
275     }
276
277     fn projected_ty_from_poly_trait_ref(
278         &self,
279         span: Span,
280         item_def_id: DefId,
281         item_segment: &hir::PathSegment<'_>,
282         poly_trait_ref: ty::PolyTraitRef<'tcx>,
283     ) -> Ty<'tcx> {
284         let trait_ref = self.replace_bound_vars_with_fresh_vars(
285             span,
286             infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
287             poly_trait_ref,
288         );
289
290         let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
291             self,
292             span,
293             item_def_id,
294             item_segment,
295             trait_ref.substs,
296         );
297
298         self.tcx().mk_projection(item_def_id, item_substs)
299     }
300
301     fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
302         if ty.has_escaping_bound_vars() {
303             ty // FIXME: normalization and escaping regions
304         } else {
305             self.normalize(span, ty)
306         }
307     }
308
309     fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
310         self.infcx.set_tainted_by_errors(e)
311     }
312
313     fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
314         self.write_ty(hir_id, ty)
315     }
316 }