]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
bump version to 1.74.1+dfsg1-1~bpo12+pve1
[rustc.git] / compiler / rustc_hir_typeck / src / fn_ctxt / mod.rs
1 mod _impl;
2 mod adjust_fulfillment_errors;
3 mod arg_matrix;
4 mod checks;
5 mod suggestions;
6
7 pub use _impl::*;
8 use rustc_errors::ErrorGuaranteed;
9 pub use suggestions::*;
10
11 use crate::coercion::DynamicCoerceMany;
12 use crate::{Diverges, EnclosingBreakables, Inherited};
13 use rustc_hir as hir;
14 use rustc_hir::def_id::{DefId, LocalDefId};
15 use rustc_hir_analysis::astconv::AstConv;
16 use rustc_infer::infer;
17 use rustc_infer::infer::error_reporting::TypeErrCtxt;
18 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
19 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
20 use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
21 use rustc_session::Session;
22 use rustc_span::symbol::Ident;
23 use rustc_span::{self, Span, DUMMY_SP};
24 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
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: LocalDefId,
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 /// 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 an `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 pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
110
111 pub(super) inh: &'a Inherited<'tcx>,
112
113 pub(super) fallback_has_occurred: Cell<bool>,
114 }
115
116 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
117 pub fn new(
118 inh: &'a Inherited<'tcx>,
119 param_env: ty::ParamEnv<'tcx>,
120 body_id: LocalDefId,
121 ) -> FnCtxt<'a, 'tcx> {
122 FnCtxt {
123 body_id,
124 param_env,
125 err_count_on_creation: inh.tcx.sess.err_count(),
126 ret_coercion: None,
127 ret_coercion_span: Cell::new(None),
128 resume_yield_tys: None,
129 diverges: Cell::new(Diverges::Maybe),
130 enclosing_breakables: RefCell::new(EnclosingBreakables {
131 stack: Vec::new(),
132 by_id: Default::default(),
133 }),
134 inh,
135 fallback_has_occurred: Cell::new(false),
136 }
137 }
138
139 pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
140 ObligationCause::new(span, self.body_id, code)
141 }
142
143 pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
144 self.cause(span, ObligationCauseCode::MiscObligation)
145 }
146
147 pub fn sess(&self) -> &Session {
148 &self.tcx.sess
149 }
150
151 /// Creates an `TypeErrCtxt` with a reference to the in-progress
152 /// `TypeckResults` which is used for diagnostics.
153 /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`.
154 ///
155 /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
156 pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
157 TypeErrCtxt {
158 infcx: &self.infcx,
159 typeck_results: Some(self.typeck_results.borrow()),
160 fallback_has_occurred: self.fallback_has_occurred.get(),
161 normalize_fn_sig: Box::new(|fn_sig| {
162 if fn_sig.has_escaping_bound_vars() {
163 return fn_sig;
164 }
165 self.probe(|_| {
166 let ocx = ObligationCtxt::new(self);
167 let normalized_fn_sig =
168 ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
169 if ocx.select_all_or_error().is_empty() {
170 let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig);
171 if !normalized_fn_sig.has_infer() {
172 return normalized_fn_sig;
173 }
174 }
175 fn_sig
176 })
177 }),
178 autoderef_steps: Box::new(|ty| {
179 let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors();
180 let mut steps = vec![];
181 while let Some((ty, _)) = autoderef.next() {
182 steps.push((ty, autoderef.current_obligations()));
183 }
184 steps
185 }),
186 }
187 }
188
189 pub fn errors_reported_since_creation(&self) -> bool {
190 self.tcx.sess.err_count() > self.err_count_on_creation
191 }
192
193 pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
194 Ty::new_var(self.tcx, self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT))
195 }
196 }
197
198 impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
199 type Target = Inherited<'tcx>;
200 fn deref(&self) -> &Self::Target {
201 &self.inh
202 }
203 }
204
205 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
206 fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
207 self.tcx
208 }
209
210 fn item_def_id(&self) -> DefId {
211 self.body_id.to_def_id()
212 }
213
214 fn get_type_parameter_bounds(
215 &self,
216 _: Span,
217 def_id: LocalDefId,
218 _: Ident,
219 ) -> ty::GenericPredicates<'tcx> {
220 let tcx = self.tcx;
221 let item_def_id = tcx.hir().ty_param_owner(def_id);
222 let generics = tcx.generics_of(item_def_id);
223 let index = generics.param_def_id_to_index[&def_id.to_def_id()];
224 ty::GenericPredicates {
225 parent: None,
226 predicates: tcx.arena.alloc_from_iter(
227 self.param_env.caller_bounds().iter().filter_map(|predicate| {
228 match predicate.kind().skip_binder() {
229 ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
230 // HACK(eddyb) should get the original `Span`.
231 let span = tcx.def_span(def_id);
232 Some((predicate, span))
233 }
234 _ => None,
235 }
236 }),
237 ),
238 }
239 }
240
241 fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
242 let v = match def {
243 Some(def) => infer::EarlyBoundRegion(span, def.name),
244 None => infer::MiscVariable(span),
245 };
246 Some(self.next_region_var(v))
247 }
248
249 fn allow_ty_infer(&self) -> bool {
250 true
251 }
252
253 fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
254 match param {
255 Some(param) => self.var_for_def(span, param).as_type().unwrap(),
256 None => self.next_ty_var(TypeVariableOrigin {
257 kind: TypeVariableOriginKind::TypeInference,
258 span,
259 }),
260 }
261 }
262
263 fn ct_infer(
264 &self,
265 ty: Ty<'tcx>,
266 param: Option<&ty::GenericParamDef>,
267 span: Span,
268 ) -> Const<'tcx> {
269 // FIXME ideally this shouldn't use unwrap
270 match param {
271 Some(
272 param @ ty::GenericParamDef {
273 kind: ty::GenericParamDefKind::Const { is_host_effect: true, .. },
274 ..
275 },
276 ) => self.var_for_effect(param).as_const().unwrap(),
277 Some(param) => self.var_for_def(span, param).as_const().unwrap(),
278 None => self.next_const_var(
279 ty,
280 ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
281 ),
282 }
283 }
284
285 fn projected_ty_from_poly_trait_ref(
286 &self,
287 span: Span,
288 item_def_id: DefId,
289 item_segment: &hir::PathSegment<'_>,
290 poly_trait_ref: ty::PolyTraitRef<'tcx>,
291 ) -> Ty<'tcx> {
292 let trait_ref = self.instantiate_binder_with_fresh_vars(
293 span,
294 infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
295 poly_trait_ref,
296 );
297
298 let item_args = self.astconv().create_args_for_associated_item(
299 span,
300 item_def_id,
301 item_segment,
302 trait_ref.args,
303 );
304
305 Ty::new_projection(self.tcx(), item_def_id, item_args)
306 }
307
308 fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
309 match ty.kind() {
310 ty::Adt(adt_def, _) => Some(*adt_def),
311 // FIXME(#104767): Should we handle bound regions here?
312 ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _)
313 if !ty.has_escaping_bound_vars() =>
314 {
315 self.normalize(span, ty).ty_adt_def()
316 }
317 _ => None,
318 }
319 }
320
321 fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
322 self.infcx.set_tainted_by_errors(e)
323 }
324
325 fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
326 // FIXME: normalization and escaping regions
327 let ty = if !ty.has_escaping_bound_vars() {
328 // NOTE: These obligations are 100% redundant and are implied by
329 // WF obligations that are registered elsewhere, but they have a
330 // better cause code assigned to them in `add_required_obligations_for_hir`.
331 // This means that they should shadow obligations with worse spans.
332 if let ty::Alias(ty::Projection | ty::Weak, ty::AliasTy { args, def_id, .. }) =
333 ty.kind()
334 {
335 self.add_required_obligations_for_hir(span, *def_id, args, hir_id);
336 }
337
338 self.normalize(span, ty)
339 } else {
340 ty
341 };
342 self.write_ty(hir_id, ty)
343 }
344
345 fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
346 Some(&self.infcx)
347 }
348 }
349
350 /// Represents a user-provided type in the raw form (never normalized).
351 ///
352 /// This is a bridge between the interface of `AstConv`, which outputs a raw `Ty`,
353 /// and the API in this module, which expect `Ty` to be fully normalized.
354 #[derive(Clone, Copy, Debug)]
355 pub struct RawTy<'tcx> {
356 pub raw: Ty<'tcx>,
357
358 /// The normalized form of `raw`, stored here for efficiency.
359 pub normalized: Ty<'tcx>,
360 }