7 use rustc_errors::ErrorGuaranteed;
8 pub use suggestions::*;
10 use crate::coercion::DynamicCoerceMany;
11 use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
13 use rustc_hir::def_id::DefId;
14 use rustc_hir_analysis::astconv::AstConv;
15 use rustc_infer::infer;
16 use rustc_infer::infer::error_reporting::TypeErrCtxt;
17 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
18 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
19 use rustc_middle::ty::subst::GenericArgKind;
20 use rustc_middle::ty::visit::TypeVisitable;
21 use rustc_middle::ty::{self, Const, Ty, TyCtxt};
22 use rustc_session::Session;
23 use rustc_span::symbol::Ident;
24 use rustc_span::{self, Span};
25 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
27 use std::cell::{Cell, RefCell};
30 /// The `FnCtxt` stores type-checking context needed to type-check bodies of
31 /// functions, closures, and `const`s, including performing type inference
32 /// with [`InferCtxt`].
34 /// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures*
35 /// and thus does not perform type inference.
37 /// See [`ItemCtxt`]'s docs for more.
39 /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
40 /// [`InferCtxt`]: infer::InferCtxt
41 pub struct FnCtxt<'a, 'tcx> {
42 pub(super) body_id: hir::HirId,
44 /// The parameter environment used for proving trait obligations
45 /// in this function. This can change when we descend into
46 /// closures (as they bring new things into scope), hence it is
47 /// not part of `Inherited` (as of the time of this writing,
48 /// closures do not yet change the environment, but they will
50 pub(super) param_env: ty::ParamEnv<'tcx>,
52 /// Number of errors that had been reported when we started
53 /// checking this function. On exit, if we find that *more* errors
54 /// have been reported, we will skip regionck and other work that
55 /// expects the types within the function to be consistent.
56 // FIXME(matthewjasper) This should not exist, and it's not correct
57 // if type checking is run in parallel.
58 err_count_on_creation: usize,
60 /// If `Some`, this stores coercion information for returned
61 /// expressions. If `None`, this is in a context where return is
62 /// inappropriate, such as a const expression.
64 /// This is a `RefCell<DynamicCoerceMany>`, which means that we
65 /// can track all the return expressions and then use them to
66 /// compute a useful coercion from the set, similar to a match
67 /// expression or other branching context. You can use methods
68 /// like `expected_ty` to access the declared return type (if
70 pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
72 /// First span of a return site that we find. Used in error messages.
73 pub(super) ret_coercion_span: Cell<Option<Span>>,
75 pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
77 pub(super) ps: Cell<UnsafetyState>,
79 /// Whether the last checked node generates a divergence (e.g.,
80 /// `return` will set this to `Always`). In general, when entering
81 /// an expression or other node in the tree, the initial value
82 /// indicates whether prior parts of the containing expression may
83 /// have diverged. It is then typically set to `Maybe` (and the
84 /// old value remembered) for processing the subparts of the
85 /// current expression. As each subpart is processed, they may set
86 /// the flag to `Always`, etc. Finally, at the end, we take the
87 /// result and "union" it with the original value, so that when we
88 /// return the flag indicates if any subpart of the parent
89 /// expression (up to and including this part) has diverged. So,
90 /// if you read it after evaluating a subexpression `X`, the value
91 /// you get indicates whether any subexpression that was
92 /// evaluating up to and including `X` diverged.
94 /// We currently use this flag only for diagnostic purposes:
96 /// - To warn about unreachable code: if, after processing a
97 /// sub-expression but before we have applied the effects of the
98 /// current node, we see that the flag is set to `Always`, we
99 /// can issue a warning. This corresponds to something like
100 /// `foo(return)`; we warn on the `foo()` expression. (We then
101 /// update the flag to `WarnedAlways` to suppress duplicate
102 /// reports.) Similarly, if we traverse to a fresh statement (or
103 /// tail expression) from an `Always` setting, we will issue a
104 /// warning. This corresponds to something like `{return;
105 /// foo();}` or `{return; 22}`, where we would warn on the
108 /// An expression represents dead code if, after checking it,
109 /// the diverges flag is set to something other than `Maybe`.
110 pub(super) diverges: Cell<Diverges>,
112 pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
114 pub(super) inh: &'a Inherited<'tcx>,
116 pub(super) fallback_has_occurred: Cell<bool>,
119 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
121 inh: &'a Inherited<'tcx>,
122 param_env: ty::ParamEnv<'tcx>,
124 ) -> FnCtxt<'a, 'tcx> {
128 err_count_on_creation: inh.tcx.sess.err_count(),
130 ret_coercion_span: Cell::new(None),
131 resume_yield_tys: None,
132 ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
133 diverges: Cell::new(Diverges::Maybe),
134 enclosing_breakables: RefCell::new(EnclosingBreakables {
136 by_id: Default::default(),
139 fallback_has_occurred: Cell::new(false),
143 pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
144 ObligationCause::new(span, self.body_id, code)
147 pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
148 self.cause(span, ObligationCauseCode::MiscObligation)
151 pub fn sess(&self) -> &Session {
155 /// Creates an `TypeErrCtxt` with a reference to the in-progress
156 /// `TypeckResults` which is used for diagnostics.
157 /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`.
159 /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
160 pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
163 typeck_results: Some(self.typeck_results.borrow()),
164 fallback_has_occurred: self.fallback_has_occurred.get(),
165 normalize_fn_sig: Box::new(|fn_sig| {
166 if fn_sig.has_escaping_bound_vars() {
170 let ocx = ObligationCtxt::new_in_snapshot(self);
171 let normalized_fn_sig =
172 ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
173 if ocx.select_all_or_error().is_empty() {
174 let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig);
175 if !normalized_fn_sig.needs_infer() {
176 return normalized_fn_sig;
185 pub fn errors_reported_since_creation(&self) -> bool {
186 self.tcx.sess.err_count() > self.err_count_on_creation
190 impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
191 type Target = Inherited<'tcx>;
192 fn deref(&self) -> &Self::Target {
197 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
198 fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
202 fn item_def_id(&self) -> DefId {
203 self.body_id.owner.to_def_id()
206 fn get_type_parameter_bounds(
211 ) -> ty::GenericPredicates<'tcx> {
213 let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
214 let generics = tcx.generics_of(item_def_id);
215 let index = generics.param_def_id_to_index[&def_id];
216 ty::GenericPredicates {
218 predicates: tcx.arena.alloc_from_iter(
219 self.param_env.caller_bounds().iter().filter_map(|predicate| {
220 match predicate.kind().skip_binder() {
221 ty::PredicateKind::Clause(ty::Clause::Trait(data))
222 if data.self_ty().is_param(index) =>
224 // HACK(eddyb) should get the original `Span`.
225 let span = tcx.def_span(def_id);
226 Some((predicate, span))
235 fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
237 Some(def) => infer::EarlyBoundRegion(span, def.name),
238 None => infer::MiscVariable(span),
240 Some(self.next_region_var(v))
243 fn allow_ty_infer(&self) -> bool {
247 fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
248 if let Some(param) = param {
249 if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
254 self.next_ty_var(TypeVariableOrigin {
255 kind: TypeVariableOriginKind::TypeInference,
264 param: Option<&ty::GenericParamDef>,
267 if let Some(param) = param {
268 if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
275 ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
280 fn projected_ty_from_poly_trait_ref(
284 item_segment: &hir::PathSegment<'_>,
285 poly_trait_ref: ty::PolyTraitRef<'tcx>,
287 let trait_ref = self.replace_bound_vars_with_fresh_vars(
289 infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
293 let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
301 self.tcx().mk_projection(item_def_id, item_substs)
304 fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
305 if ty.has_escaping_bound_vars() {
306 ty // FIXME: normalization and escaping regions
308 self.normalize(span, ty)
312 fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
313 self.infcx.set_tainted_by_errors(e)
316 fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
317 self.write_ty(hir_id, ty)