]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
Auto merge of #101562 - nnethercote:shrink-ast-Expr-harder, r=petrochenkov
[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 pub use suggestions::*;
8
9 use crate::coercion::DynamicCoerceMany;
10 use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
11 use rustc_hir as hir;
12 use rustc_hir::def_id::DefId;
13 use rustc_hir_analysis::astconv::AstConv;
14 use rustc_infer::infer;
15 use rustc_infer::infer::error_reporting::TypeErrCtxt;
16 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
17 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
18 use rustc_middle::ty::subst::GenericArgKind;
19 use rustc_middle::ty::visit::TypeVisitable;
20 use rustc_middle::ty::{self, Const, Ty, TyCtxt};
21 use rustc_session::Session;
22 use rustc_span::symbol::Ident;
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
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 ///
38 /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
39 /// [`InferCtxt`]: infer::InferCtxt
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
71     /// First span of a return site that we find. Used in error messages.
72     pub(super) ret_coercion_span: Cell<Option<Span>>,
73
74     pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
75
76     pub(super) ps: Cell<UnsafetyState>,
77
78     /// Whether the last checked node generates a divergence (e.g.,
79     /// `return` will set this to `Always`). In general, when entering
80     /// an expression or other node in the tree, the initial value
81     /// indicates whether prior parts of the containing expression may
82     /// have diverged. It is then typically set to `Maybe` (and the
83     /// old value remembered) for processing the subparts of the
84     /// current expression. As each subpart is processed, they may set
85     /// the flag to `Always`, etc. Finally, at the end, we take the
86     /// result and "union" it with the original value, so that when we
87     /// return the flag indicates if any subpart of the parent
88     /// expression (up to and including this part) has diverged. So,
89     /// if you read it after evaluating a subexpression `X`, the value
90     /// you get indicates whether any subexpression that was
91     /// evaluating up to and including `X` diverged.
92     ///
93     /// We currently use this flag only for diagnostic purposes:
94     ///
95     /// - To warn about unreachable code: if, after processing a
96     ///   sub-expression but before we have applied the effects of the
97     ///   current node, we see that the flag is set to `Always`, we
98     ///   can issue a warning. This corresponds to something like
99     ///   `foo(return)`; we warn on the `foo()` expression. (We then
100     ///   update the flag to `WarnedAlways` to suppress duplicate
101     ///   reports.) Similarly, if we traverse to a fresh statement (or
102     ///   tail expression) from an `Always` setting, we will issue a
103     ///   warning. This corresponds to something like `{return;
104     ///   foo();}` or `{return; 22}`, where we would warn on the
105     ///   `foo()` or `22`.
106     ///
107     /// An expression represents dead code if, after checking it,
108     /// the diverges flag is set to something other than `Maybe`.
109     pub(super) diverges: Cell<Diverges>,
110
111     pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
112
113     pub(super) inh: &'a Inherited<'tcx>,
114
115     pub(super) fallback_has_occurred: Cell<bool>,
116 }
117
118 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
119     pub fn new(
120         inh: &'a Inherited<'tcx>,
121         param_env: ty::ParamEnv<'tcx>,
122         body_id: hir::HirId,
123     ) -> FnCtxt<'a, 'tcx> {
124         FnCtxt {
125             body_id,
126             param_env,
127             err_count_on_creation: inh.tcx.sess.err_count(),
128             ret_coercion: None,
129             ret_coercion_span: Cell::new(None),
130             resume_yield_tys: None,
131             ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
132             diverges: Cell::new(Diverges::Maybe),
133             enclosing_breakables: RefCell::new(EnclosingBreakables {
134                 stack: Vec::new(),
135                 by_id: Default::default(),
136             }),
137             inh,
138             fallback_has_occurred: Cell::new(false),
139         }
140     }
141
142     pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
143         ObligationCause::new(span, self.body_id, code)
144     }
145
146     pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
147         self.cause(span, ObligationCauseCode::MiscObligation)
148     }
149
150     pub fn sess(&self) -> &Session {
151         &self.tcx.sess
152     }
153
154     /// Creates an `TypeErrCtxt` with a reference to the in-progress
155     /// `TypeckResults` which is used for diagnostics.
156     /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`.
157     ///
158     /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
159     pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
160         TypeErrCtxt {
161             infcx: &self.infcx,
162             typeck_results: Some(self.typeck_results.borrow()),
163             fallback_has_occurred: self.fallback_has_occurred.get(),
164         }
165     }
166
167     pub fn errors_reported_since_creation(&self) -> bool {
168         self.tcx.sess.err_count() > self.err_count_on_creation
169     }
170 }
171
172 impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
173     type Target = Inherited<'tcx>;
174     fn deref(&self) -> &Self::Target {
175         &self.inh
176     }
177 }
178
179 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
180     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
181         self.tcx
182     }
183
184     fn item_def_id(&self) -> DefId {
185         self.body_id.owner.to_def_id()
186     }
187
188     fn get_type_parameter_bounds(
189         &self,
190         _: Span,
191         def_id: DefId,
192         _: Ident,
193     ) -> ty::GenericPredicates<'tcx> {
194         let tcx = self.tcx;
195         let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
196         let generics = tcx.generics_of(item_def_id);
197         let index = generics.param_def_id_to_index[&def_id];
198         ty::GenericPredicates {
199             parent: None,
200             predicates: tcx.arena.alloc_from_iter(
201                 self.param_env.caller_bounds().iter().filter_map(|predicate| {
202                     match predicate.kind().skip_binder() {
203                         ty::PredicateKind::Trait(data) if data.self_ty().is_param(index) => {
204                             // HACK(eddyb) should get the original `Span`.
205                             let span = tcx.def_span(def_id);
206                             Some((predicate, span))
207                         }
208                         _ => None,
209                     }
210                 }),
211             ),
212         }
213     }
214
215     fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
216         let v = match def {
217             Some(def) => infer::EarlyBoundRegion(span, def.name),
218             None => infer::MiscVariable(span),
219         };
220         Some(self.next_region_var(v))
221     }
222
223     fn allow_ty_infer(&self) -> bool {
224         true
225     }
226
227     fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
228         if let Some(param) = param {
229             if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
230                 return ty;
231             }
232             unreachable!()
233         } else {
234             self.next_ty_var(TypeVariableOrigin {
235                 kind: TypeVariableOriginKind::TypeInference,
236                 span,
237             })
238         }
239     }
240
241     fn ct_infer(
242         &self,
243         ty: Ty<'tcx>,
244         param: Option<&ty::GenericParamDef>,
245         span: Span,
246     ) -> Const<'tcx> {
247         if let Some(param) = param {
248             if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
249                 return ct;
250             }
251             unreachable!()
252         } else {
253             self.next_const_var(
254                 ty,
255                 ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
256             )
257         }
258     }
259
260     fn projected_ty_from_poly_trait_ref(
261         &self,
262         span: Span,
263         item_def_id: DefId,
264         item_segment: &hir::PathSegment<'_>,
265         poly_trait_ref: ty::PolyTraitRef<'tcx>,
266     ) -> Ty<'tcx> {
267         let trait_ref = self.replace_bound_vars_with_fresh_vars(
268             span,
269             infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
270             poly_trait_ref,
271         );
272
273         let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
274             self,
275             span,
276             item_def_id,
277             item_segment,
278             trait_ref.substs,
279         );
280
281         self.tcx().mk_projection(item_def_id, item_substs)
282     }
283
284     fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
285         if ty.has_escaping_bound_vars() {
286             ty // FIXME: normalization and escaping regions
287         } else {
288             self.normalize_associated_types_in(span, ty)
289         }
290     }
291
292     fn set_tainted_by_errors(&self) {
293         self.infcx.set_tainted_by_errors()
294     }
295
296     fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
297         self.write_ty(hir_id, ty)
298     }
299 }