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