]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / compiler / rustc_hir_typeck / src / fn_ctxt / mod.rs
CommitLineData
29967ef6 1mod _impl;
923072b8 2mod arg_matrix;
29967ef6
XL
3mod checks;
4mod suggestions;
5
6pub use _impl::*;
29967ef6
XL
7pub use suggestions::*;
8
2b03887a
FG
9use crate::coercion::DynamicCoerceMany;
10use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
29967ef6
XL
11use rustc_hir as hir;
12use rustc_hir::def_id::DefId;
2b03887a 13use rustc_hir_analysis::astconv::AstConv;
29967ef6 14use rustc_infer::infer;
2b03887a 15use rustc_infer::infer::error_reporting::TypeErrCtxt;
29967ef6 16use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
5e7ed085 17use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
29967ef6 18use rustc_middle::ty::subst::GenericArgKind;
064997fb 19use rustc_middle::ty::visit::TypeVisitable;
29967ef6
XL
20use rustc_middle::ty::{self, Const, Ty, TyCtxt};
21use rustc_session::Session;
6a06907d 22use rustc_span::symbol::Ident;
29967ef6
XL
23use rustc_span::{self, Span};
24use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
25
26use std::cell::{Cell, RefCell};
27use 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
40pub 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
132impl<'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
185impl<'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
192impl<'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}