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