2 mod adjust_fulfillment_errors
;
8 use rustc_errors
::ErrorGuaranteed
;
9 pub use suggestions
::*;
11 use crate::coercion
::DynamicCoerceMany
;
12 use crate::{Diverges, EnclosingBreakables, Inherited}
;
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}
;
26 use std
::cell
::{Cell, RefCell}
;
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`].
33 /// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures*
34 /// and thus does not perform type inference.
36 /// See [`ItemCtxt`]'s docs for more.
38 /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
39 /// [`InferCtxt`]: infer::InferCtxt
40 pub struct FnCtxt
<'a
, 'tcx
> {
41 pub(super) body_id
: LocalDefId
,
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
49 pub(super) param_env
: ty
::ParamEnv
<'tcx
>,
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,
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.
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
69 pub(super) ret_coercion
: Option
<RefCell
<DynamicCoerceMany
<'tcx
>>>,
71 /// First span of a return site that we find. Used in error messages.
72 pub(super) ret_coercion_span
: Cell
<Option
<Span
>>,
74 pub(super) resume_yield_tys
: Option
<(Ty
<'tcx
>, Ty
<'tcx
>)>,
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.
91 /// We currently use this flag only for diagnostic purposes:
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
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
>,
109 pub(super) enclosing_breakables
: RefCell
<EnclosingBreakables
<'tcx
>>,
111 pub(super) inh
: &'a Inherited
<'tcx
>,
113 pub(super) fallback_has_occurred
: Cell
<bool
>,
116 impl<'a
, 'tcx
> FnCtxt
<'a
, 'tcx
> {
118 inh
: &'a Inherited
<'tcx
>,
119 param_env
: ty
::ParamEnv
<'tcx
>,
121 ) -> FnCtxt
<'a
, 'tcx
> {
125 err_count_on_creation
: inh
.tcx
.sess
.err_count(),
127 ret_coercion_span
: Cell
::new(None
),
128 resume_yield_tys
: None
,
129 diverges
: Cell
::new(Diverges
::Maybe
),
130 enclosing_breakables
: RefCell
::new(EnclosingBreakables
{
132 by_id
: Default
::default(),
135 fallback_has_occurred
: Cell
::new(false),
139 pub fn cause(&self, span
: Span
, code
: ObligationCauseCode
<'tcx
>) -> ObligationCause
<'tcx
> {
140 ObligationCause
::new(span
, self.body_id
, code
)
143 pub fn misc(&self, span
: Span
) -> ObligationCause
<'tcx
> {
144 self.cause(span
, ObligationCauseCode
::MiscObligation
)
147 pub fn sess(&self) -> &Session
{
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`.
155 /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
156 pub fn err_ctxt(&'a
self) -> TypeErrCtxt
<'a
, 'tcx
> {
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() {
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
;
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()));
189 pub fn errors_reported_since_creation(&self) -> bool
{
190 self.tcx
.sess
.err_count() > self.err_count_on_creation
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
))
198 impl<'a
, 'tcx
> Deref
for FnCtxt
<'a
, 'tcx
> {
199 type Target
= Inherited
<'tcx
>;
200 fn deref(&self) -> &Self::Target
{
205 impl<'a
, 'tcx
> AstConv
<'tcx
> for FnCtxt
<'a
, 'tcx
> {
206 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'tcx
> {
210 fn item_def_id(&self) -> DefId
{
211 self.body_id
.to_def_id()
214 fn get_type_parameter_bounds(
219 ) -> ty
::GenericPredicates
<'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
{
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
))
241 fn re_infer(&self, def
: Option
<&ty
::GenericParamDef
>, span
: Span
) -> Option
<ty
::Region
<'tcx
>> {
243 Some(def
) => infer
::EarlyBoundRegion(span
, def
.name
),
244 None
=> infer
::MiscVariable(span
),
246 Some(self.next_region_var(v
))
249 fn allow_ty_infer(&self) -> bool
{
253 fn ty_infer(&self, param
: Option
<&ty
::GenericParamDef
>, span
: Span
) -> Ty
<'tcx
> {
255 Some(param
) => self.var_for_def(span
, param
).as_type().unwrap(),
256 None
=> self.next_ty_var(TypeVariableOrigin
{
257 kind
: TypeVariableOriginKind
::TypeInference
,
266 param
: Option
<&ty
::GenericParamDef
>,
269 // FIXME ideally this shouldn't use unwrap
272 param @ ty
::GenericParamDef
{
273 kind
: ty
::GenericParamDefKind
::Const { is_host_effect: true, .. }
,
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(
280 ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }
,
285 fn projected_ty_from_poly_trait_ref(
289 item_segment
: &hir
::PathSegment
<'_
>,
290 poly_trait_ref
: ty
::PolyTraitRef
<'tcx
>,
292 let trait_ref
= self.instantiate_binder_with_fresh_vars(
294 infer
::LateBoundRegionConversionTime
::AssocTypeProjection(item_def_id
),
298 let item_args
= self.astconv().create_args_for_associated_item(
305 Ty
::new_projection(self.tcx(), item_def_id
, item_args
)
308 fn probe_adt(&self, span
: Span
, ty
: Ty
<'tcx
>) -> Option
<ty
::AdtDef
<'tcx
>> {
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() =>
315 self.normalize(span
, ty
).ty_adt_def()
321 fn set_tainted_by_errors(&self, e
: ErrorGuaranteed
) {
322 self.infcx
.set_tainted_by_errors(e
)
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, .. }
) =
335 self.add_required_obligations_for_hir(span
, *def_id
, args
, hir_id
);
338 self.normalize(span
, ty
)
342 self.write_ty(hir_id
, ty
)
345 fn infcx(&self) -> Option
<&infer
::InferCtxt
<'tcx
>> {
350 /// Represents a user-provided type in the raw form (never normalized).
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
> {
358 /// The normalized form of `raw`, stored here for efficiency.
359 pub normalized
: Ty
<'tcx
>,