Skip to main content

rustc_hir_typeck/fn_ctxt/
mod.rs

1mod _impl;
2mod adjust_fulfillment_errors;
3mod arg_matrix;
4mod checks;
5mod inspect_obligations;
6mod suggestions;
7
8use std::cell::{Cell, RefCell};
9use std::ops::Deref;
10
11use rustc_errors::DiagCtxtHandle;
12use rustc_hir::attrs::{DivergingBlockBehavior, DivergingFallbackBehavior};
13use rustc_hir::def_id::{DefId, LocalDefId};
14use rustc_hir::{self as hir, HirId, ItemLocalMap, find_attr};
15use rustc_hir_analysis::hir_ty_lowering::{
16    HirTyLowerer, InherentAssocCandidate, RegionInferReason,
17};
18use rustc_infer::infer::{self, RegionVariableOrigin};
19use rustc_infer::traits::{DynCompatibilityViolation, Obligation};
20use rustc_middle::ty::{self, Const, Flags, Ty, TyCtxt, TypeVisitableExt, Unnormalized};
21use rustc_session::Session;
22use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span};
23use rustc_trait_selection::error_reporting::TypeErrCtxt;
24use rustc_trait_selection::traits::{
25    self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
26};
27
28use crate::coercion::CoerceMany;
29use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
30
31/// The `FnCtxt` stores type-checking context needed to type-check bodies of
32/// functions, closures, and `const`s, including performing type inference
33/// with [`InferCtxt`].
34///
35/// This is in contrast to `rustc_hir_analysis::collect::ItemCtxt`, which is
36/// used to type-check item *signatures* and thus does not perform type
37/// inference.
38///
39/// See `ItemCtxt`'s docs for more.
40///
41/// [`InferCtxt`]: infer::InferCtxt
42pub(crate) struct FnCtxt<'a, 'tcx> {
43    pub(super) body_id: LocalDefId,
44
45    /// The parameter environment used for proving trait obligations
46    /// in this function. This can change when we descend into
47    /// closures (as they bring new things into scope), hence it is
48    /// not part of `Inherited` (as of the time of this writing,
49    /// closures do not yet change the environment, but they will
50    /// eventually).
51    pub(super) param_env: ty::ParamEnv<'tcx>,
52
53    /// If `Some`, this stores coercion information for returned
54    /// expressions. If `None`, this is in a context where return is
55    /// inappropriate, such as a const expression.
56    ///
57    /// This is a `RefCell<CoerceMany>`, which means that we
58    /// can track all the return expressions and then use them to
59    /// compute a useful coercion from the set, similar to a match
60    /// expression or other branching context. You can use methods
61    /// like `expected_ty` to access the declared return type (if
62    /// any).
63    pub(super) ret_coercion: Option<RefCell<CoerceMany<'tcx>>>,
64
65    /// First span of a return site that we find. Used in error messages.
66    pub(super) ret_coercion_span: Cell<Option<Span>>,
67
68    pub(super) coroutine_types: Option<CoroutineTypes<'tcx>>,
69
70    /// Whether the last checked node generates a divergence (e.g.,
71    /// `return` will set this to `Always`). In general, when entering
72    /// an expression or other node in the tree, the initial value
73    /// indicates whether prior parts of the containing expression may
74    /// have diverged. It is then typically set to `Maybe` (and the
75    /// old value remembered) for processing the subparts of the
76    /// current expression. As each subpart is processed, they may set
77    /// the flag to `Always`, etc. Finally, at the end, we take the
78    /// result and "union" it with the original value, so that when we
79    /// return the flag indicates if any subpart of the parent
80    /// expression (up to and including this part) has diverged. So,
81    /// if you read it after evaluating a subexpression `X`, the value
82    /// you get indicates whether any subexpression that was
83    /// evaluating up to and including `X` diverged.
84    ///
85    /// We currently use this flag for the following purposes:
86    ///
87    /// - To warn about unreachable code: if, after processing a
88    ///   sub-expression but before we have applied the effects of the
89    ///   current node, we see that the flag is set to `Always`, we
90    ///   can issue a warning. This corresponds to something like
91    ///   `foo(return)`; we warn on the `foo()` expression. (We then
92    ///   update the flag to `WarnedAlways` to suppress duplicate
93    ///   reports.) Similarly, if we traverse to a fresh statement (or
94    ///   tail expression) from an `Always` setting, we will issue a
95    ///   warning. This corresponds to something like `{return;
96    ///   foo();}` or `{return; 22}`, where we would warn on the
97    ///   `foo()` or `22`.
98    /// - To assign the `!` type to block expressions with diverging
99    ///   statements.
100    ///
101    /// An expression represents dead code if, after checking it,
102    /// the diverges flag is set to something other than `Maybe`.
103    pub(super) diverges: Cell<Diverges>,
104
105    /// If one of the function arguments is a never pattern, this counts as diverging code.
106    /// This affect typechecking of the function body.
107    pub(super) function_diverges_because_of_empty_arguments: Cell<Diverges>,
108
109    /// Whether the currently checked node is the whole body of the function.
110    pub(super) is_whole_body: Cell<bool>,
111
112    pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
113
114    pub(super) root_ctxt: &'a TypeckRootCtxt<'tcx>,
115
116    /// True if a divirging inference variable has been set to `()`/`!` because
117    /// of never type fallback. This is only used for diagnostics.
118    pub(super) diverging_fallback_has_occurred: Cell<bool>,
119
120    pub(super) diverging_fallback_behavior: DivergingFallbackBehavior,
121    pub(super) diverging_block_behavior: DivergingBlockBehavior,
122
123    /// Clauses that we lowered as part of the `impl_trait_in_bindings` feature.
124    ///
125    /// These are stored here so we may collect them when canonicalizing user
126    /// type ascriptions later.
127    pub(super) trait_ascriptions: RefCell<ItemLocalMap<Vec<ty::Clause<'tcx>>>>,
128
129    /// Whether the current crate enables the `rustc_attrs` feature.
130    /// This allows to skip processing attributes in many places.
131    pub(super) has_rustc_attrs: bool,
132}
133
134impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
135    pub(crate) fn new(
136        root_ctxt: &'a TypeckRootCtxt<'tcx>,
137        param_env: ty::ParamEnv<'tcx>,
138        body_id: LocalDefId,
139    ) -> FnCtxt<'a, 'tcx> {
140        let (diverging_fallback_behavior, diverging_block_behavior) =
141            never_type_behavior(root_ctxt.tcx);
142        FnCtxt {
143            body_id,
144            param_env,
145            ret_coercion: None,
146            ret_coercion_span: Cell::new(None),
147            coroutine_types: None,
148            diverges: Cell::new(Diverges::Maybe),
149            function_diverges_because_of_empty_arguments: Cell::new(Diverges::Maybe),
150            is_whole_body: Cell::new(false),
151            enclosing_breakables: RefCell::new(EnclosingBreakables {
152                stack: Vec::new(),
153                by_id: Default::default(),
154            }),
155            root_ctxt,
156            diverging_fallback_has_occurred: Cell::new(false),
157            diverging_fallback_behavior,
158            diverging_block_behavior,
159            trait_ascriptions: Default::default(),
160            has_rustc_attrs: root_ctxt.tcx.features().rustc_attrs(),
161        }
162    }
163
164    pub(crate) fn dcx(&self) -> DiagCtxtHandle<'a> {
165        self.root_ctxt.infcx.dcx()
166    }
167
168    pub(crate) fn cause(
169        &self,
170        span: Span,
171        code: ObligationCauseCode<'tcx>,
172    ) -> ObligationCause<'tcx> {
173        ObligationCause::new(span, self.body_id, code)
174    }
175
176    pub(crate) fn misc(&self, span: Span) -> ObligationCause<'tcx> {
177        self.cause(span, ObligationCauseCode::Misc)
178    }
179
180    pub(crate) fn sess(&self) -> &Session {
181        self.tcx.sess
182    }
183
184    /// Creates an `TypeErrCtxt` with a reference to the in-progress
185    /// `TypeckResults` which is used for diagnostics.
186    /// Use [`InferCtxtErrorExt::err_ctxt`] to start one without a `TypeckResults`.
187    ///
188    /// [`InferCtxtErrorExt::err_ctxt`]: rustc_trait_selection::error_reporting::InferCtxtErrorExt::err_ctxt
189    pub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
190        TypeErrCtxt {
191            infcx: &self.infcx,
192            typeck_results: Some(self.typeck_results.borrow()),
193            diverging_fallback_has_occurred: self.diverging_fallback_has_occurred.get(),
194            normalize_fn_sig: Box::new(|fn_sig| {
195                if fn_sig.skip_normalization().has_escaping_bound_vars() {
196                    return fn_sig.skip_normalization();
197                }
198                self.probe(|_| {
199                    let ocx = ObligationCtxt::new(self);
200                    let normalized_fn_sig =
201                        ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
202                    if ocx.evaluate_obligations_error_on_ambiguity().is_empty() {
203                        let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig);
204                        if !normalized_fn_sig.has_infer() {
205                            return normalized_fn_sig;
206                        }
207                    }
208                    fn_sig.skip_normalization()
209                })
210            }),
211            autoderef_steps: Box::new(|ty| {
212                let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors();
213                let mut steps = ::alloc::vec::Vec::new()vec![];
214                while let Some((ty, _)) = autoderef.next() {
215                    steps.push((ty, autoderef.current_obligations()));
216                }
217                steps
218            }),
219        }
220    }
221}
222
223impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
224    type Target = TypeckRootCtxt<'tcx>;
225    fn deref(&self) -> &Self::Target {
226        self.root_ctxt
227    }
228}
229
230impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
231    fn tcx(&self) -> TyCtxt<'tcx> {
232        self.tcx
233    }
234
235    fn dcx(&self) -> DiagCtxtHandle<'_> {
236        self.root_ctxt.dcx()
237    }
238
239    fn item_def_id(&self) -> LocalDefId {
240        self.body_id
241    }
242
243    fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
244        let v = match reason {
245            RegionInferReason::Param(def) => {
246                RegionVariableOrigin::RegionParameterDefinition(span, def.name)
247            }
248            _ => RegionVariableOrigin::Misc(span),
249        };
250        self.next_region_var(v)
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(span),
257        }
258    }
259
260    fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
261        // FIXME ideally this shouldn't use unwrap
262        match param {
263            Some(param) => self.var_for_def(span, param).as_const().unwrap(),
264            None => self.next_const_var(span),
265        }
266    }
267
268    fn register_trait_ascription_bounds(
269        &self,
270        bounds: Vec<(ty::Clause<'tcx>, Span)>,
271        hir_id: HirId,
272        _span: Span,
273    ) {
274        for (clause, span) in bounds {
275            if clause.has_escaping_bound_vars() {
276                self.dcx().span_delayed_bug(span, "clause should have no escaping bound vars");
277                continue;
278            }
279
280            self.trait_ascriptions.borrow_mut().entry(hir_id.local_id).or_default().push(clause);
281
282            let clause = self.normalize(span, Unnormalized::new_wip(clause));
283            self.register_predicate(Obligation::new(
284                self.tcx,
285                self.misc(span),
286                self.param_env,
287                clause,
288            ));
289        }
290    }
291
292    fn probe_ty_param_bounds(
293        &self,
294        _: Span,
295        def_id: LocalDefId,
296        _: Ident,
297    ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
298        let tcx = self.tcx;
299        let item_def_id = tcx.hir_ty_param_owner(def_id);
300        let generics = tcx.generics_of(item_def_id);
301        let index = generics.param_def_id_to_index[&def_id.to_def_id()];
302        // HACK(eddyb) should get the original `Span`.
303        let span = tcx.def_span(def_id);
304
305        ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(
306            self.param_env.caller_bounds().iter().filter_map(|predicate| {
307                match predicate.kind().skip_binder() {
308                    ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
309                        Some((predicate, span))
310                    }
311                    _ => None,
312                }
313            }),
314        ))
315    }
316
317    fn select_inherent_assoc_candidates(
318        &self,
319        span: Span,
320        self_ty: Ty<'tcx>,
321        candidates: Vec<InherentAssocCandidate>,
322    ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) {
323        let tcx = self.tcx();
324        let infcx = &self.infcx;
325        let mut fulfillment_errors = ::alloc::vec::Vec::new()vec![];
326
327        let mut filter_iat_candidate = |self_ty, impl_| {
328            let ocx = ObligationCtxt::new_with_diagnostics(self);
329            let self_ty = ocx.normalize(
330                &ObligationCause::dummy(),
331                self.param_env,
332                Unnormalized::new_wip(self_ty),
333            );
334
335            let impl_args = infcx.fresh_args_for_item(span, impl_);
336            let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
337            let impl_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_ty);
338
339            // Check that the self types can be related.
340            if ocx.eq(&ObligationCause::dummy(), self.param_env, impl_ty, self_ty).is_err() {
341                return false;
342            }
343
344            // Check whether the impl imposes obligations we have to worry about.
345            let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
346            let impl_obligations = traits::predicates_for_generics(
347                |_, _| ObligationCause::dummy(),
348                |pred| ocx.normalize(&ObligationCause::dummy(), self.param_env, pred),
349                self.param_env,
350                impl_bounds,
351            );
352            ocx.register_obligations(impl_obligations);
353
354            let mut errors = ocx.try_evaluate_obligations();
355            if !errors.is_empty() {
356                fulfillment_errors.append(&mut errors);
357                return false;
358            }
359
360            true
361        };
362
363        let mut universes = if self_ty.has_escaping_bound_vars() {
364            ::alloc::vec::from_elem(None, self_ty.outer_exclusive_binder().as_usize())vec![None; self_ty.outer_exclusive_binder().as_usize()]
365        } else {
366            ::alloc::vec::Vec::new()vec![]
367        };
368
369        let candidates =
370            traits::with_replaced_escaping_bound_vars(infcx, &mut universes, self_ty, |self_ty| {
371                candidates
372                    .into_iter()
373                    .filter(|&InherentAssocCandidate { impl_, .. }| {
374                        infcx.probe(|_| filter_iat_candidate(self_ty, impl_))
375                    })
376                    .collect()
377            });
378
379        (candidates, fulfillment_errors)
380    }
381
382    fn lower_assoc_item_path(
383        &self,
384        span: Span,
385        item_def_id: DefId,
386        item_segment: &rustc_hir::PathSegment<'tcx>,
387        poly_trait_ref: ty::PolyTraitRef<'tcx>,
388    ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
389        let trait_ref = self.instantiate_binder_with_fresh_vars(
390            span,
391            // FIXME(mgca): `item_def_id` can be an AssocConst; rename this variant.
392            infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id),
393            poly_trait_ref,
394        );
395
396        let item_args = self.lowerer().lower_generic_args_of_assoc_item(
397            span,
398            item_def_id,
399            item_segment,
400            trait_ref.args,
401        );
402
403        Ok((item_def_id, item_args))
404    }
405
406    fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
407        match ty.kind() {
408            ty::Adt(adt_def, _) => Some(*adt_def),
409            // FIXME(#104767): Should we handle bound regions here?
410            ty::Alias(ty::AliasTy {
411                kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
412                ..
413            }) if !ty.has_escaping_bound_vars() => {
414                if self.next_trait_solver() {
415                    self.try_structurally_resolve_type(span, ty).ty_adt_def()
416                } else {
417                    self.normalize(span, Unnormalized::new_wip(ty)).ty_adt_def()
418                }
419            }
420            _ => None,
421        }
422    }
423
424    fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
425        // FIXME: normalization and escaping regions
426        let ty = if !ty.has_escaping_bound_vars() {
427            // NOTE: These obligations are 100% redundant and are implied by
428            // WF obligations that are registered elsewhere, but they have a
429            // better cause code assigned to them in `add_required_obligations_for_hir`.
430            // This means that they should shadow obligations with worse spans.
431            if let ty::Alias(ty::AliasTy {
432                kind: ty::Projection { def_id } | ty::Free { def_id },
433                args,
434                ..
435            }) = ty.kind()
436            {
437                self.add_required_obligations_for_hir(span, *def_id, args, hir_id);
438            }
439
440            self.normalize(span, Unnormalized::new_wip(ty))
441        } else {
442            ty
443        };
444        self.write_ty(hir_id, ty)
445    }
446
447    fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
448        Some(&self.infcx)
449    }
450
451    fn lower_fn_sig(
452        &self,
453        decl: &rustc_hir::FnDecl<'tcx>,
454        _generics: Option<&rustc_hir::Generics<'_>>,
455        _hir_id: rustc_hir::HirId,
456        _hir_ty: Option<&hir::Ty<'_>>,
457    ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
458        let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_ty(a)).collect();
459
460        let output_ty = match decl.output {
461            hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output),
462            hir::FnRetTy::DefaultReturn(..) => self.tcx().types.unit,
463        };
464        (input_tys, output_ty)
465    }
466
467    fn dyn_compatibility_violations(&self, trait_def_id: DefId) -> Vec<DynCompatibilityViolation> {
468        self.tcx.dyn_compatibility_violations(trait_def_id).to_vec()
469    }
470}
471
472/// The `ty` representation of a user-provided type. Depending on the use-site
473/// we want to either use the unnormalized or the normalized form of this type.
474///
475/// This is a bridge between the interface of HIR ty lowering, which outputs a raw
476/// `Ty`, and the API in this module, which expect `Ty` to be fully normalized.
477#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for LoweredTy<'tcx> {
    #[inline]
    fn clone(&self) -> LoweredTy<'tcx> {
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for LoweredTy<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for LoweredTy<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "LoweredTy",
            "raw", &self.raw, "normalized", &&self.normalized)
    }
}Debug)]
478pub(crate) struct LoweredTy<'tcx> {
479    /// The unnormalized type provided by the user.
480    pub raw: Ty<'tcx>,
481
482    /// The normalized form of `raw`, stored here for efficiency.
483    pub normalized: Ty<'tcx>,
484}
485
486impl<'tcx> LoweredTy<'tcx> {
487    fn from_raw(fcx: &FnCtxt<'_, 'tcx>, span: Span, raw: Ty<'tcx>) -> LoweredTy<'tcx> {
488        // FIXME(-Znext-solver=no): This is easier than requiring all uses of `LoweredTy`
489        // to call `try_structurally_resolve_type` instead. This seems like a lot of
490        // effort, especially as we're still supporting the old solver. We may revisit
491        // this in the future.
492        let normalized = if fcx.next_trait_solver() {
493            fcx.try_structurally_resolve_type(span, raw)
494        } else {
495            fcx.normalize(span, Unnormalized::new_wip(raw))
496        };
497        LoweredTy { raw, normalized }
498    }
499}
500
501fn never_type_behavior(tcx: TyCtxt<'_>) -> (DivergingFallbackBehavior, DivergingBlockBehavior) {
502    let (fallback, block) = parse_never_type_options_attr(tcx);
503    let fallback = fallback.unwrap_or_else(|| default_fallback(tcx));
504    let block = block.unwrap_or_default();
505
506    (fallback, block)
507}
508
509/// Returns the default fallback which is used when there is no explicit override via `#![never_type_options(...)]`.
510fn default_fallback(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior {
511    // Edition 2024: fallback to `!`
512    if tcx.sess.edition().at_least_rust_2024() {
513        return DivergingFallbackBehavior::ToNever;
514    }
515
516    // Otherwise: fallback to `()`
517    DivergingFallbackBehavior::ToUnit
518}
519
520fn parse_never_type_options_attr(
521    tcx: TyCtxt<'_>,
522) -> (Option<DivergingFallbackBehavior>, Option<DivergingBlockBehavior>) {
523    // Error handling is dubious here (unwraps), but that's probably fine for an internal attribute.
524    // Just don't write incorrect attributes <3
525
526    {
    'done:
        {
        for i in tcx.hir_krate_attrs() {
            #[allow(unused_imports)]
            use rustc_hir::attrs::AttributeKind::*;
            let i: &rustc_hir::Attribute = i;
            match i {
                rustc_hir::Attribute::Parsed(RustcNeverTypeOptions {
                    fallback, diverging_block_default }) => {
                    break 'done Some((*fallback, *diverging_block_default));
                }
                rustc_hir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(tcx, crate, RustcNeverTypeOptions {fallback, diverging_block_default} => (*fallback, *diverging_block_default)).unwrap_or_default()
527}