Struct rustc_hir_typeck::FnCtxt
source · pub struct FnCtxt<'a, 'tcx> {
pub(crate) body_id: LocalDefId,
pub(crate) param_env: ParamEnv<'tcx>,
err_count_on_creation: usize,
pub(crate) ret_coercion: Option<RefCell<CoerceMany<'tcx, 'tcx, &'tcx Expr<'tcx>>>>,
pub(crate) ret_coercion_span: Cell<Option<Span>>,
pub(crate) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
pub(crate) diverges: Cell<Diverges>,
pub(crate) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
pub(crate) inh: &'a Inherited<'tcx>,
pub(crate) fallback_has_occurred: Cell<bool>,
}
Expand description
The FnCtxt
stores type-checking context needed to type-check bodies of
functions, closures, and const
s, including performing type inference
with InferCtxt
.
This is in contrast to ItemCtxt
, which is used to type-check item signatures
and thus does not perform type inference.
See ItemCtxt
’s docs for more.
Fields§
§body_id: LocalDefId
§param_env: ParamEnv<'tcx>
The parameter environment used for proving trait obligations
in this function. This can change when we descend into
closures (as they bring new things into scope), hence it is
not part of Inherited
(as of the time of this writing,
closures do not yet change the environment, but they will
eventually).
err_count_on_creation: usize
Number of errors that had been reported when we started checking this function. On exit, if we find that more errors have been reported, we will skip regionck and other work that expects the types within the function to be consistent.
ret_coercion: Option<RefCell<CoerceMany<'tcx, 'tcx, &'tcx Expr<'tcx>>>>
If Some
, this stores coercion information for returned
expressions. If None
, this is in a context where return is
inappropriate, such as a const expression.
This is a RefCell<DynamicCoerceMany>
, which means that we
can track all the return expressions and then use them to
compute a useful coercion from the set, similar to a match
expression or other branching context. You can use methods
like expected_ty
to access the declared return type (if
any).
ret_coercion_span: Cell<Option<Span>>
First span of a return site that we find. Used in error messages.
resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>
§diverges: Cell<Diverges>
Whether the last checked node generates a divergence (e.g.,
return
will set this to Always
). In general, when entering
an expression or other node in the tree, the initial value
indicates whether prior parts of the containing expression may
have diverged. It is then typically set to Maybe
(and the
old value remembered) for processing the subparts of the
current expression. As each subpart is processed, they may set
the flag to Always
, etc. Finally, at the end, we take the
result and “union” it with the original value, so that when we
return the flag indicates if any subpart of the parent
expression (up to and including this part) has diverged. So,
if you read it after evaluating a subexpression X
, the value
you get indicates whether any subexpression that was
evaluating up to and including X
diverged.
We currently use this flag only for diagnostic purposes:
- To warn about unreachable code: if, after processing a
sub-expression but before we have applied the effects of the
current node, we see that the flag is set to
Always
, we can issue a warning. This corresponds to something likefoo(return)
; we warn on thefoo()
expression. (We then update the flag toWarnedAlways
to suppress duplicate reports.) Similarly, if we traverse to a fresh statement (or tail expression) from anAlways
setting, we will issue a warning. This corresponds to something like{return; foo();}
or{return; 22}
, where we would warn on thefoo()
or22
.
An expression represents dead code if, after checking it,
the diverges flag is set to something other than Maybe
.
enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>
§inh: &'a Inherited<'tcx>
§fallback_has_occurred: Cell<bool>
Implementations§
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn check_match( &self, expr: &'tcx Expr<'tcx>, scrut: &'tcx Expr<'tcx>, arms: &'tcx [Arm<'tcx>], orig_expected: Expectation<'tcx>, match_src: MatchSource ) -> Ty<'tcx>
fn suggest_removing_semicolon_for_coerce( &self, diag: &mut Diagnostic, expr: &Expr<'tcx>, arm_ty: Ty<'tcx>, prior_arm: Option<(Option<HirId>, Ty<'tcx>, Span)> )
sourcefn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [Arm<'tcx>])
fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [Arm<'tcx>])
When the previously checked expression (the scrutinee) diverges, warn the user about the match arms being unreachable.
sourcepub(crate) fn if_fallback_coercion<T>(
&self,
span: Span,
then_expr: &'tcx Expr<'tcx>,
coercion: &mut CoerceMany<'tcx, '_, T>
) -> boolwhere
T: AsCoercionSite,
pub(crate) fn if_fallback_coercion<T>( &self, span: Span, then_expr: &'tcx Expr<'tcx>, coercion: &mut CoerceMany<'tcx, '_, T> ) -> boolwhere T: AsCoercionSite,
Handle the fallback arm of a desugared if(-let) like a missing else.
Returns true
if there was an error forcing the coercion to the ()
type.
pub fn maybe_get_coercion_reason( &self, hir_id: HirId, sp: Span ) -> Option<(Span, String)>
pub(crate) fn if_cause( &self, span: Span, cond_span: Span, then_expr: &'tcx Expr<'tcx>, else_expr: &'tcx Expr<'tcx>, then_ty: Ty<'tcx>, else_ty: Ty<'tcx>, opt_suggest_box_span: Option<Span> ) -> ObligationCause<'tcx>
pub(crate) fn demand_scrutinee_type( &self, scrut: &'tcx Expr<'tcx>, contains_ref_bindings: Option<Mutability>, no_arms: bool ) -> Ty<'tcx>
sourcepub(crate) fn opt_suggest_box_span(
&self,
first_ty: Ty<'tcx>,
second_ty: Ty<'tcx>,
orig_expected: Expectation<'tcx>
) -> Option<Span>
pub(crate) fn opt_suggest_box_span( &self, first_ty: Ty<'tcx>, second_ty: Ty<'tcx>, orig_expected: Expectation<'tcx> ) -> Option<Span>
When we have a match
as a tail expression in a fn
with a returned impl Trait
we check if the different arms would work with boxed trait objects instead and
provide a structured suggestion in that case.
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx>
pub fn try_overloaded_deref( &self, span: Span, base_ty: Ty<'tcx> ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
sourcepub fn adjust_steps(
&self,
autoderef: &Autoderef<'a, 'tcx>
) -> Vec<Adjustment<'tcx>>
pub fn adjust_steps( &self, autoderef: &Autoderef<'a, 'tcx> ) -> Vec<Adjustment<'tcx>>
Returns the adjustment steps.
pub fn adjust_steps_as_infer_ok( &self, autoderef: &Autoderef<'a, 'tcx> ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>>
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn check_call( &self, call_expr: &'tcx Expr<'tcx>, callee_expr: &'tcx Expr<'tcx>, arg_exprs: &'tcx [Expr<'tcx>], expected: Expectation<'tcx> ) -> Ty<'tcx>
fn try_overloaded_call_step( &self, call_expr: &'tcx Expr<'tcx>, callee_expr: &'tcx Expr<'tcx>, arg_exprs: &'tcx [Expr<'tcx>], autoderef: &Autoderef<'a, 'tcx> ) -> Option<CallStep<'tcx>>
fn try_overloaded_call_traits( &self, call_expr: &Expr<'_>, adjusted_ty: Ty<'tcx>, opt_arg_exprs: Option<&'tcx [Expr<'tcx>]> ) -> Option<(Option<Adjustment<'tcx>>, MethodCallee<'tcx>)>
sourcefn identify_bad_closure_def_and_call(
&self,
err: &mut Diagnostic,
hir_id: HirId,
callee_node: &ExprKind<'_>,
callee_span: Span
)
fn identify_bad_closure_def_and_call( &self, err: &mut Diagnostic, hir_id: HirId, callee_node: &ExprKind<'_>, callee_span: Span )
Give appropriate suggestion when encountering ||{/* not callable */}()
, where the
likely intention is to call the closure, suggest (||{})()
. (#55851)
sourcefn maybe_suggest_bad_array_definition(
&self,
err: &mut Diagnostic,
call_expr: &'tcx Expr<'tcx>,
callee_expr: &'tcx Expr<'tcx>
) -> bool
fn maybe_suggest_bad_array_definition( &self, err: &mut Diagnostic, call_expr: &'tcx Expr<'tcx>, callee_expr: &'tcx Expr<'tcx> ) -> bool
Give appropriate suggestion when encountering [("a", 0) ("b", 1)]
, where the
likely intention is to create an array containing tuples.
fn confirm_builtin_call( &self, call_expr: &'tcx Expr<'tcx>, callee_expr: &'tcx Expr<'tcx>, callee_ty: Ty<'tcx>, arg_exprs: &'tcx [Expr<'tcx>], expected: Expectation<'tcx> ) -> Ty<'tcx>
sourcefn suggest_call_as_method(
&self,
diag: &mut Diagnostic,
segment: &'tcx PathSegment<'tcx>,
arg_exprs: &'tcx [Expr<'tcx>],
call_expr: &'tcx Expr<'tcx>,
expected: Expectation<'tcx>
)
fn suggest_call_as_method( &self, diag: &mut Diagnostic, segment: &'tcx PathSegment<'tcx>, arg_exprs: &'tcx [Expr<'tcx>], call_expr: &'tcx Expr<'tcx>, expected: Expectation<'tcx> )
Attempts to reinterpret method(rcvr, args...)
as rcvr.method(args...)
and suggesting the fix if the method probe is successful.
fn report_invalid_callee( &self, call_expr: &'tcx Expr<'tcx>, callee_expr: &'tcx Expr<'tcx>, callee_ty: Ty<'tcx>, arg_exprs: &'tcx [Expr<'tcx>] ) -> ErrorGuaranteed
fn confirm_deferred_closure_call( &self, call_expr: &'tcx Expr<'tcx>, arg_exprs: &'tcx [Expr<'tcx>], expected: Expectation<'tcx>, closure_def_id: LocalDefId, fn_sig: FnSig<'tcx> ) -> Ty<'tcx>
pub(crate) fn enforce_context_effects( &self, call_expr_hir: HirId, span: Span, callee_did: DefId, callee_args: GenericArgsRef<'tcx> )
fn confirm_overloaded_call( &self, call_expr: &'tcx Expr<'tcx>, arg_exprs: &'tcx [Expr<'tcx>], expected: Expectation<'tcx>, method_callee: MethodCallee<'tcx> ) -> Ty<'tcx>
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
sourcefn pointer_kind(
&self,
t: Ty<'tcx>,
span: Span
) -> Result<Option<PointerKind<'tcx>>, ErrorGuaranteed>
fn pointer_kind( &self, t: Ty<'tcx>, span: Span ) -> Result<Option<PointerKind<'tcx>>, ErrorGuaranteed>
Returns the kind of unsize information of t, or None if t is unknown.
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn check_expr_closure( &self, closure: &Closure<'tcx>, expr_span: Span, expected: Expectation<'tcx> ) -> Ty<'tcx>
fn check_closure( &self, closure: &Closure<'tcx>, expr_span: Span, opt_kind: Option<ClosureKind>, body: &'tcx Body<'tcx>, expected_sig: Option<ExpectedSig<'tcx>> ) -> Ty<'tcx>
sourcefn deduce_closure_signature(
&self,
expected_ty: Ty<'tcx>
) -> (Option<ExpectedSig<'tcx>>, Option<ClosureKind>)
fn deduce_closure_signature( &self, expected_ty: Ty<'tcx> ) -> (Option<ExpectedSig<'tcx>>, Option<ClosureKind>)
Given the expected type, figures out what it can about this closure we are about to type check:
fn deduce_closure_signature_from_predicates( &self, expected_ty: Ty<'tcx>, predicates: impl DoubleEndedIterator<Item = (Predicate<'tcx>, Span)> ) -> (Option<ExpectedSig<'tcx>>, Option<ClosureKind>)
sourcefn deduce_sig_from_projection(
&self,
cause_span: Option<Span>,
projection: PolyProjectionPredicate<'tcx>
) -> Option<ExpectedSig<'tcx>>
fn deduce_sig_from_projection( &self, cause_span: Option<Span>, projection: PolyProjectionPredicate<'tcx> ) -> Option<ExpectedSig<'tcx>>
Given a projection like “<F as Fn(X)>::Result == Y”, we can deduce everything we need to know about a closure or generator.
The cause_span
should be the span that caused us to
have this expected signature, or None
if we can’t readily
know that.
fn sig_of_closure( &self, expr_def_id: LocalDefId, decl: &FnDecl<'_>, body: &Body<'_>, expected_sig: Option<ExpectedSig<'tcx>> ) -> ClosureSignatures<'tcx>
sourcefn sig_of_closure_no_expectation(
&self,
expr_def_id: LocalDefId,
decl: &FnDecl<'_>,
body: &Body<'_>
) -> ClosureSignatures<'tcx>
fn sig_of_closure_no_expectation( &self, expr_def_id: LocalDefId, decl: &FnDecl<'_>, body: &Body<'_> ) -> ClosureSignatures<'tcx>
If there is no expected signature, then we will convert the types that the user gave into a signature.
sourcefn sig_of_closure_with_expectation(
&self,
expr_def_id: LocalDefId,
decl: &FnDecl<'_>,
body: &Body<'_>,
expected_sig: ExpectedSig<'tcx>
) -> ClosureSignatures<'tcx>
fn sig_of_closure_with_expectation( &self, expr_def_id: LocalDefId, decl: &FnDecl<'_>, body: &Body<'_>, expected_sig: ExpectedSig<'tcx> ) -> ClosureSignatures<'tcx>
Invoked to compute the signature of a closure expression. This
combines any user-provided type annotations (e.g., |x: u32| -> u32 { .. }
) with the expected signature.
The approach is as follows:
- Let
S
be the (higher-ranked) signature that we derive from the user’s annotations. - Let
E
be the (higher-ranked) signature that we derive from the expectations, if any.- If we have no expectation
E
, then the signature of the closure isS
. - Otherwise, the signature of the closure is E. Moreover:
- Skolemize the late-bound regions in
E
, yieldingE'
. - Instantiate all the late-bound regions bound in the closure within
S
with fresh (existential) variables, yieldingS'
- Require that
E' = S'
- We could use some kind of subtyping relationship here, I imagine, but equality is easier and works fine for our purposes.
- Skolemize the late-bound regions in
- If we have no expectation
The key intuition here is that the user’s types must be valid from “the inside” of the closure, but the expectation ultimately drives the overall signature.
Examples
fn with_closure<F>(_: F)
where F: Fn(&u32) -> &u32 { .. }
with_closure(|x: &u32| { ... })
Here:
- E would be
fn(&u32) -> &u32
. - S would be
fn(&u32) -> ?T
- E’ is
&'!0 u32 -> &'!0 u32
- S’ is
&'?0 u32 -> ?T
S’ can be unified with E’ with ['?0 = '!0, ?T = &'!10 u32]
.
Arguments
expr_def_id
: theLocalDefId
of the closure expressiondecl
: the HIR declaration of the closurebody
: the body of the closureexpected_sig
: the expected signature (if any). Note that this is missing a binder: that is, there may be late-bound regions with depth 1, which are bound then by the closure.
fn sig_of_closure_with_mismatched_number_of_arguments( &self, expr_def_id: LocalDefId, decl: &FnDecl<'_>, body: &Body<'_>, expected_sig: ExpectedSig<'tcx> ) -> ClosureSignatures<'tcx>
sourcefn merge_supplied_sig_with_expectation(
&self,
expr_def_id: LocalDefId,
decl: &FnDecl<'_>,
body: &Body<'_>,
expected_sigs: ClosureSignatures<'tcx>
) -> InferResult<'tcx, ClosureSignatures<'tcx>>
fn merge_supplied_sig_with_expectation( &self, expr_def_id: LocalDefId, decl: &FnDecl<'_>, body: &Body<'_>, expected_sigs: ClosureSignatures<'tcx> ) -> InferResult<'tcx, ClosureSignatures<'tcx>>
Enforce the user’s types against the expectation. See
sig_of_closure_with_expectation
for details on the overall
strategy.
sourcefn supplied_sig_of_closure(
&self,
expr_def_id: LocalDefId,
decl: &FnDecl<'_>,
body: &Body<'_>
) -> PolyFnSig<'tcx>
fn supplied_sig_of_closure( &self, expr_def_id: LocalDefId, decl: &FnDecl<'_>, body: &Body<'_> ) -> PolyFnSig<'tcx>
If there is no expected signature, then we will convert the types that the user gave into a signature.
Also, record this closure signature for later.
sourcefn deduce_future_output_from_obligations(
&self,
expr_def_id: LocalDefId,
body_def_id: LocalDefId
) -> Option<Ty<'tcx>>
fn deduce_future_output_from_obligations( &self, expr_def_id: LocalDefId, body_def_id: LocalDefId ) -> Option<Ty<'tcx>>
Invoked when we are translating the generator that results
from desugaring an async fn
. Returns the “sugared” return
type of the async fn
– that is, the return type that the
user specified. The “desugared” return type is an impl Future<Output = T>
, so we do this by searching through the
obligations to extract the T
.
sourcefn deduce_future_output_from_projection(
&self,
cause_span: Span,
predicate: PolyProjectionPredicate<'tcx>
) -> Option<Ty<'tcx>>
fn deduce_future_output_from_projection( &self, cause_span: Span, predicate: PolyProjectionPredicate<'tcx> ) -> Option<Ty<'tcx>>
Given a projection like
<X as Future>::Output = T
where X
is some type that has no late-bound regions, returns
Some(T)
. If the projection is for some other trait, returns
None
.
sourcefn error_sig_of_closure(
&self,
decl: &FnDecl<'_>,
guar: ErrorGuaranteed
) -> PolyFnSig<'tcx>
fn error_sig_of_closure( &self, decl: &FnDecl<'_>, guar: ErrorGuaranteed ) -> PolyFnSig<'tcx>
Converts the types that the user supplied, in case that doing
so should yield an error, but returns back a signature where
all parameters are of type ty::Error
.
fn closure_sigs( &self, expr_def_id: LocalDefId, body: &Body<'_>, bound_sig: PolyFnSig<'tcx> ) -> ClosureSignatures<'tcx>
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
sourcepub fn coerce(
&self,
expr: &Expr<'_>,
expr_ty: Ty<'tcx>,
target: Ty<'tcx>,
allow_two_phase: AllowTwoPhase,
cause: Option<ObligationCause<'tcx>>
) -> RelateResult<'tcx, Ty<'tcx>>
pub fn coerce( &self, expr: &Expr<'_>, expr_ty: Ty<'tcx>, target: Ty<'tcx>, allow_two_phase: AllowTwoPhase, cause: Option<ObligationCause<'tcx>> ) -> RelateResult<'tcx, Ty<'tcx>>
Attempt to coerce an expression to a type, and return the adjusted type of the expression, if successful. Adjustments are only recorded if the coercion succeeded. The expressions must not have any preexisting adjustments.
sourcepub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool
pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool
Same as coerce()
, but without side-effects.
Returns false if the coercion creates any obligations that result in errors.
sourcepub fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option<usize>
pub fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option<usize>
Given a type and a target type, this function will calculate and return
how many dereference steps needed to achieve expr_ty <: target
. If
it’s not possible, return None
.
sourcepub fn deref_once_mutably_for_diagnostic(
&self,
expr_ty: Ty<'tcx>
) -> Option<Ty<'tcx>>
pub fn deref_once_mutably_for_diagnostic( &self, expr_ty: Ty<'tcx> ) -> Option<Ty<'tcx>>
Given a type, this function will calculate and return the type given
for <Ty as Deref>::Target
only if Ty
also implements DerefMut
.
This function is for diagnostics only, since it does not register trait or region sub-obligations. (presumably we could, but it’s not particularly important for diagnostics…)
sourcefn try_find_coercion_lub<E>(
&self,
cause: &ObligationCause<'tcx>,
exprs: &[E],
prev_ty: Ty<'tcx>,
new: &Expr<'_>,
new_ty: Ty<'tcx>
) -> RelateResult<'tcx, Ty<'tcx>>where
E: AsCoercionSite,
fn try_find_coercion_lub<E>( &self, cause: &ObligationCause<'tcx>, exprs: &[E], prev_ty: Ty<'tcx>, new: &Expr<'_>, new_ty: Ty<'tcx> ) -> RelateResult<'tcx, Ty<'tcx>>where E: AsCoercionSite,
Given some expressions, their known unified type and another expression, tries to unify the types, potentially inserting coercions on any of the provided expressions and returns their LUB (aka “common supertype”).
This is really an internal helper. From outside the coercion
module, you should instantiate a CoerceMany
instance.
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn emit_type_mismatch_suggestions( &self, err: &mut Diagnostic, expr: &Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>>, error: Option<TypeError<'tcx>> )
pub fn emit_coerce_suggestions( &self, err: &mut Diagnostic, expr: &Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>>, error: Option<TypeError<'tcx>> )
sourcefn adjust_expr_for_assert_eq_macro(
&self,
found_expr: &mut &'tcx Expr<'tcx>,
expected_expr: &mut Option<&'tcx Expr<'tcx>>
)
fn adjust_expr_for_assert_eq_macro( &self, found_expr: &mut &'tcx Expr<'tcx>, expected_expr: &mut Option<&'tcx Expr<'tcx>> )
Really hacky heuristic to remap an assert_eq!
error to the user
expressions provided to the macro.
sourcepub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>)
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>)
Requires that the two types unify, and prints an error message if they don’t.
pub fn demand_suptype_diag( &self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx> ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>
pub fn demand_suptype_with_origin( &self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx> ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>
pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>)
pub fn demand_eqtype_diag( &self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx> ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>
pub fn demand_eqtype_with_origin( &self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx> ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>
pub fn demand_coerce( &self, expr: &'tcx Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>>, allow_two_phase: AllowTwoPhase ) -> Ty<'tcx>
sourcepub fn demand_coerce_diag(
&self,
expr: &'tcx Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx Expr<'tcx>>,
allow_two_phase: AllowTwoPhase
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>)
pub fn demand_coerce_diag( &self, expr: &'tcx Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>>, allow_two_phase: AllowTwoPhase ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>)
Checks that the type of expr
can be coerced to expected
.
N.B., this code relies on self.diverges
to be accurate. In particular, assignments to !
will be permitted if the diverges flag is currently “always”.
sourcepub fn note_source_of_type_mismatch_constraint(
&self,
err: &mut Diagnostic,
expr: &Expr<'_>,
source: TypeMismatchSource<'tcx>
) -> bool
pub fn note_source_of_type_mismatch_constraint( &self, err: &mut Diagnostic, expr: &Expr<'_>, source: TypeMismatchSource<'tcx> ) -> bool
Notes the point at which a variable is constrained to some type incompatible
with some expectation given by source
.
pub fn annotate_loop_expected_due_to_inference( &self, err: &mut Diagnostic, expr: &Expr<'_>, error: Option<TypeError<'tcx>> )
fn annotate_expected_due_to_let_ty( &self, err: &mut Diagnostic, expr: &Expr<'_>, error: Option<TypeError<'tcx>> )
fn annotate_alternative_method_deref( &self, err: &mut Diagnostic, expr: &Expr<'_>, error: Option<TypeError<'tcx>> )
pub(crate) fn suggest_coercing_result_via_try_operator( &self, err: &mut Diagnostic, expr: &Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx> ) -> bool
sourcefn suggest_compatible_variants(
&self,
err: &mut Diagnostic,
expr: &Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>
) -> bool
fn suggest_compatible_variants( &self, err: &mut Diagnostic, expr: &Expr<'_>, expected: Ty<'tcx>, expr_ty: Ty<'tcx> ) -> bool
If the expected type is an enum (Issue #55250) with any variants whose sole field is of the found type, suggest such variants. (Issue #42764)
fn suggest_non_zero_new_unwrap( &self, err: &mut Diagnostic, expr: &Expr<'_>, expected: Ty<'tcx>, expr_ty: Ty<'tcx> ) -> bool
pub fn get_conversion_methods( &self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>, hir_id: HirId ) -> Vec<AssocItem>
sourcefn has_only_self_parameter(&self, method: &AssocItem) -> bool
fn has_only_self_parameter(&self, method: &AssocItem) -> bool
This function checks whether the method is not static and does not accept other parameters than self
.
sourcefn can_use_as_ref(
&self,
expr: &Expr<'_>
) -> Option<(Vec<(Span, String)>, &'static str)>
fn can_use_as_ref( &self, expr: &Expr<'_> ) -> Option<(Vec<(Span, String)>, &'static str)>
Identify some cases where as_ref()
would be appropriate and suggest it.
Given the following code:
struct Foo;
fn takes_ref(_: &Foo) {}
let ref opt = Some(Foo);
opt.map(|param| takes_ref(param));
Suggest using opt.as_ref().map(|param| takes_ref(param));
instead.
It only checks for Option
and Result
and won’t work with
opt.map(|param| { takes_ref(param) });
sourcepub(crate) fn maybe_get_block_expr(
&self,
expr: &Expr<'tcx>
) -> Option<&'tcx Expr<'tcx>>
pub(crate) fn maybe_get_block_expr( &self, expr: &Expr<'tcx> ) -> Option<&'tcx Expr<'tcx>>
If the given HirId
corresponds to a block with a trailing expression, return that expression
sourcepub(crate) fn is_else_if_block(&self, expr: &Expr<'_>) -> bool
pub(crate) fn is_else_if_block(&self, expr: &Expr<'_>) -> bool
Returns whether the given expression is an else if
.
pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &Expr<'_>) -> bool
sourcepub fn suggest_deref_or_ref(
&self,
expr: &Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>
) -> Option<(Vec<(Span, String)>, String, Applicability, bool, bool)>
pub fn suggest_deref_or_ref( &self, expr: &Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx> ) -> Option<(Vec<(Span, String)>, String, Applicability, bool, bool)>
This function is used to determine potential “simple” improvements or users’ errors and provide them useful help. For example:
fn some_fn(s: &str) {}
let x = "hey!".to_owned();
some_fn(x); // error
No need to find every potential function which could make a coercion to transform a
String
into a &str
since a &
would do the trick!
In addition of this check, it also checks between references mutability state. If the
expected is mutable but the provided isn’t, maybe we could just say “Hey, try with
&mut
!”.
pub fn suggest_cast( &self, err: &mut Diagnostic, expr: &Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>> ) -> bool
sourcepub fn suggest_method_call_on_range_literal(
&self,
err: &mut Diagnostic,
expr: &Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>
)
pub fn suggest_method_call_on_range_literal( &self, err: &mut Diagnostic, expr: &Expr<'tcx>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx> )
Identify when the user has written foo..bar()
instead of foo.bar()
.
sourcefn suggest_return_binding_for_missing_tail_expr(
&self,
err: &mut Diagnostic,
expr: &Expr<'_>,
checked_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>
)
fn suggest_return_binding_for_missing_tail_expr( &self, err: &mut Diagnostic, expr: &Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx> )
Identify when the type error is because ()
is found in a binding that was assigned a
block without a tail expression.
fn note_wrong_return_ty_due_to_generic_arg( &self, err: &mut Diagnostic, expr: &Expr<'_>, checked_ty: Ty<'tcx> )
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn check_expr_has_type_or_error( &self, expr: &'tcx Expr<'tcx>, expected_ty: Ty<'tcx>, extend_err: impl FnOnce(&mut Diagnostic) ) -> Ty<'tcx>
pub(crate) fn check_expr_coercible_to_type( &self, expr: &'tcx Expr<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>> ) -> Ty<'tcx>
pub(crate) fn check_expr_with_hint( &self, expr: &'tcx Expr<'tcx>, expected: Ty<'tcx> ) -> Ty<'tcx>
fn check_expr_with_expectation_and_needs( &self, expr: &'tcx Expr<'tcx>, expected: Expectation<'tcx>, needs: Needs ) -> Ty<'tcx>
pub(crate) fn check_expr(&self, expr: &'tcx Expr<'tcx>) -> Ty<'tcx>
pub(crate) fn check_expr_with_needs( &self, expr: &'tcx Expr<'tcx>, needs: Needs ) -> Ty<'tcx>
sourcepub(crate) fn check_expr_with_expectation(
&self,
expr: &'tcx Expr<'tcx>,
expected: Expectation<'tcx>
) -> Ty<'tcx>
pub(crate) fn check_expr_with_expectation( &self, expr: &'tcx Expr<'tcx>, expected: Expectation<'tcx> ) -> Ty<'tcx>
Invariant:
If an expression has any sub-expressions that result in a type error,
inspecting that expression’s type with ty.references_error()
will return
true. Likewise, if an expression is known to diverge, inspecting its
type with ty::type_is_bot
will return true (n.b.: since Rust is
strict, | can appear in the type of an expression that does not,
itself, diverge: for example, fn() -> |.)
Note that inspecting a type’s structure directly may expose the fact
that there are actually multiple representations for Error
, so avoid
that when err needs to be handled differently.
sourcepub(crate) fn check_expr_with_expectation_and_args(
&self,
expr: &'tcx Expr<'tcx>,
expected: Expectation<'tcx>,
args: &'tcx [Expr<'tcx>]
) -> Ty<'tcx>
pub(crate) fn check_expr_with_expectation_and_args( &self, expr: &'tcx Expr<'tcx>, expected: Expectation<'tcx>, args: &'tcx [Expr<'tcx>] ) -> Ty<'tcx>
Same as check_expr_with_expectation
, but allows us to pass in the arguments of a
ExprKind::Call
when evaluating its callee when it is an ExprKind::Path
.
fn check_expr_kind( &self, expr: &'tcx Expr<'tcx>, expected: Expectation<'tcx> ) -> Ty<'tcx>
fn check_expr_unary( &self, unop: UnOp, oprnd: &'tcx Expr<'tcx>, expected: Expectation<'tcx>, expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
fn check_expr_addr_of( &self, kind: BorrowKind, mutbl: Mutability, oprnd: &'tcx Expr<'tcx>, expected: Expectation<'tcx>, expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
sourcefn check_named_place_expr(&self, oprnd: &'tcx Expr<'tcx>)
fn check_named_place_expr(&self, oprnd: &'tcx Expr<'tcx>)
Does this expression refer to a place that either:
- Is based on a local or static.
- Contains a dereference
Note that the adjustments for the children of
expr
should already have been resolved.
fn check_lang_item_path( &self, lang_item: LangItem, expr: &'tcx Expr<'tcx>, hir_id: Option<HirId> ) -> Ty<'tcx>
pub(crate) fn check_expr_path( &self, qpath: &'tcx QPath<'tcx>, expr: &'tcx Expr<'tcx>, args: &'tcx [Expr<'tcx>] ) -> Ty<'tcx>
fn check_expr_break( &self, destination: Destination, expr_opt: Option<&'tcx Expr<'tcx>>, expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
fn check_expr_return( &self, expr_opt: Option<&'tcx Expr<'tcx>>, expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
fn check_expr_become( &self, call: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
sourcepub(crate) fn check_return_expr(
&self,
return_expr: &'tcx Expr<'tcx>,
explicit_return: bool
)
pub(crate) fn check_return_expr( &self, return_expr: &'tcx Expr<'tcx>, explicit_return: bool )
Check an expression that is being returned.
For example, this is called with return_expr: $expr
when return $expr
is encountered.
Note that this function must only be called in function bodies.
explicit_return
is true
if we’re checking an explicit return expr
,
and false
if we’re checking a trailing expression.
sourcefn emit_return_outside_of_fn_body(
&self,
expr: &Expr<'_>,
kind: ReturnLikeStatementKind
)
fn emit_return_outside_of_fn_body( &self, expr: &Expr<'_>, kind: ReturnLikeStatementKind )
Emit an error because return
or become
is used outside of a function body.
expr
is the return
(become
) “statement”, kind
is the kind of the statement
either Return
or Become
.
fn point_at_return_for_opaque_ty_error( &self, errors: &mut Vec<FulfillmentError<'tcx>>, span: Span, return_expr_ty: Ty<'tcx>, return_span: Span )
pub(crate) fn check_lhs_assignable( &self, lhs: &'tcx Expr<'tcx>, err_code: &'static str, op_span: Span, adjust_err: impl FnOnce(&mut Diagnostic) )
sourcepub(crate) fn comes_from_while_condition(
&self,
original_expr_id: HirId,
then: impl FnOnce(&Expr<'_>)
)
pub(crate) fn comes_from_while_condition( &self, original_expr_id: HirId, then: impl FnOnce(&Expr<'_>) )
as opposed from the body of a while loop, which we can naively check by iterating parents until we find a loop…
fn check_then_else( &self, cond_expr: &'tcx Expr<'tcx>, then_expr: &'tcx Expr<'tcx>, opt_else_expr: Option<&'tcx Expr<'tcx>>, sp: Span, orig_expected: Expectation<'tcx> ) -> Ty<'tcx>
sourcefn check_expr_assign(
&self,
expr: &'tcx Expr<'tcx>,
expected: Expectation<'tcx>,
lhs: &'tcx Expr<'tcx>,
rhs: &'tcx Expr<'tcx>,
span: Span
) -> Ty<'tcx>
fn check_expr_assign( &self, expr: &'tcx Expr<'tcx>, expected: Expectation<'tcx>, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>, span: Span ) -> Ty<'tcx>
Type check assignment expression expr
of form lhs = rhs
.
The expected type is ()
and is passed to the function for the purposes of diagnostics.
pub(crate) fn check_expr_let(&self, let_expr: &'tcx Let<'tcx>) -> Ty<'tcx>
fn check_expr_loop( &self, body: &'tcx Block<'tcx>, source: LoopSource, expected: Expectation<'tcx>, expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
sourcefn check_method_call(
&self,
expr: &'tcx Expr<'tcx>,
segment: &PathSegment<'_>,
rcvr: &'tcx Expr<'tcx>,
args: &'tcx [Expr<'tcx>],
expected: Expectation<'tcx>
) -> Ty<'tcx>
fn check_method_call( &self, expr: &'tcx Expr<'tcx>, segment: &PathSegment<'_>, rcvr: &'tcx Expr<'tcx>, args: &'tcx [Expr<'tcx>], expected: Expectation<'tcx> ) -> Ty<'tcx>
Checks a method call.
fn check_expr_cast( &self, e: &'tcx Expr<'tcx>, t: &'tcx Ty<'tcx>, expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
fn check_expr_array( &self, args: &'tcx [Expr<'tcx>], expected: Expectation<'tcx>, expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
fn suggest_array_len(&self, expr: &'tcx Expr<'tcx>, array_len: u64)
fn check_expr_const_block( &self, block: &'tcx ConstBlock, expected: Expectation<'tcx>, _expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
fn check_expr_repeat( &self, element: &'tcx Expr<'tcx>, count: &'tcx ArrayLen, expected: Expectation<'tcx>, expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
fn check_repeat_element_needs_copy_bound( &self, element: &Expr<'_>, count: Const<'tcx>, element_ty: Ty<'tcx> )
fn check_expr_tuple( &self, elts: &'tcx [Expr<'tcx>], expected: Expectation<'tcx>, expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
fn check_expr_struct( &self, expr: &Expr<'_>, expected: Expectation<'tcx>, qpath: &QPath<'_>, fields: &'tcx [ExprField<'tcx>], base_expr: &'tcx Option<&'tcx Expr<'tcx>> ) -> Ty<'tcx>
fn check_expr_struct_fields( &self, adt_ty: Ty<'tcx>, expected: Expectation<'tcx>, expr: &Expr<'_>, span: Span, variant: &'tcx VariantDef, ast_fields: &'tcx [ExprField<'tcx>], base_expr: &'tcx Option<&'tcx Expr<'tcx>> )
fn check_struct_fields_on_error( &self, fields: &'tcx [ExprField<'tcx>], base_expr: &'tcx Option<&'tcx Expr<'tcx>> )
sourcefn report_missing_fields(
&self,
adt_ty: Ty<'tcx>,
span: Span,
remaining_fields: FxHashMap<Ident, (FieldIdx, &FieldDef)>,
variant: &'tcx VariantDef,
ast_fields: &'tcx [ExprField<'tcx>],
args: GenericArgsRef<'tcx>
)
fn report_missing_fields( &self, adt_ty: Ty<'tcx>, span: Span, remaining_fields: FxHashMap<Ident, (FieldIdx, &FieldDef)>, variant: &'tcx VariantDef, ast_fields: &'tcx [ExprField<'tcx>], args: GenericArgsRef<'tcx> )
Report an error for a struct field expression when there are fields which aren’t provided.
error: missing field `you_can_use_this_field` in initializer of `foo::Foo`
--> src/main.rs:8:5
|
8 | foo::Foo {};
| ^^^^^^^^ missing `you_can_use_this_field`
error: aborting due to previous error
sourcefn suggest_fru_from_range(
&self,
last_expr_field: &ExprField<'tcx>,
variant: &VariantDef,
args: GenericArgsRef<'tcx>,
err: &mut Diagnostic
)
fn suggest_fru_from_range( &self, last_expr_field: &ExprField<'tcx>, variant: &VariantDef, args: GenericArgsRef<'tcx>, err: &mut Diagnostic )
If the last field is a range literal, but it isn’t supposed to be, then they probably meant to use functional update syntax.
sourcefn report_private_fields(
&self,
adt_ty: Ty<'tcx>,
span: Span,
private_fields: Vec<&FieldDef>,
used_fields: &'tcx [ExprField<'tcx>]
)
fn report_private_fields( &self, adt_ty: Ty<'tcx>, span: Span, private_fields: Vec<&FieldDef>, used_fields: &'tcx [ExprField<'tcx>] )
Report an error for a struct field expression when there are invisible fields.
error: cannot construct `Foo` with struct literal syntax due to private fields
--> src/main.rs:8:5
|
8 | foo::Foo {};
| ^^^^^^^^
error: aborting due to previous error
fn report_unknown_field( &self, ty: Ty<'tcx>, variant: &'tcx VariantDef, expr: &Expr<'_>, field: &ExprField<'_>, skip_fields: &[ExprField<'_>], kind_name: &str ) -> ErrorGuaranteed
fn available_field_names( &self, variant: &'tcx VariantDef, expr: &Expr<'_>, skip_fields: &[ExprField<'_>] ) -> Vec<Symbol>
fn name_series_display(&self, names: Vec<Symbol>) -> String
fn check_field( &self, expr: &'tcx Expr<'tcx>, base: &'tcx Expr<'tcx>, field: Ident, expected: Expectation<'tcx> ) -> Ty<'tcx>
fn suggest_await_on_field_access( &self, err: &mut Diagnostic, field_ident: Ident, base: &'tcx Expr<'tcx>, ty: Ty<'tcx> )
fn ban_nonexisting_field( &self, ident: Ident, base: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx>, base_ty: Ty<'tcx> ) -> ErrorGuaranteed
fn ban_private_field_access( &self, expr: &Expr<'tcx>, expr_t: Ty<'tcx>, field: Ident, base_did: DefId, return_ty: Option<Ty<'tcx>> ) -> ErrorGuaranteed
fn ban_take_value_of_method( &self, expr: &Expr<'tcx>, expr_t: Ty<'tcx>, field: Ident ) -> ErrorGuaranteed
fn point_at_param_definition(&self, err: &mut Diagnostic, param: ParamTy)
fn suggest_fields_on_recordish( &self, err: &mut Diagnostic, expr: &Expr<'_>, def: AdtDef<'tcx>, field: Ident )
fn maybe_suggest_array_indexing( &self, err: &mut Diagnostic, expr: &Expr<'_>, base: &Expr<'_>, field: Ident, len: Const<'tcx> )
fn suggest_first_deref_field( &self, err: &mut Diagnostic, expr: &Expr<'_>, base: &Expr<'_>, field: Ident )
fn no_such_field_err( &self, field: Ident, expr_t: Ty<'tcx>, id: HirId ) -> DiagnosticBuilder<'_, ErrorGuaranteed>
fn private_field_err( &self, field: Ident, base_did: DefId ) -> DiagnosticBuilder<'_, ErrorGuaranteed>
pub(crate) fn get_field_candidates_considering_privacy( &self, span: Span, base_ty: Ty<'tcx>, mod_id: DefId ) -> Option<(impl Iterator<Item = &'tcx FieldDef> + 'tcx, GenericArgsRef<'tcx>)>
sourcepub(crate) fn check_for_nested_field_satisfying(
&self,
span: Span,
matches: &impl Fn(&FieldDef, Ty<'tcx>) -> bool,
candidate_field: &FieldDef,
subst: GenericArgsRef<'tcx>,
field_path: Vec<Ident>,
mod_id: DefId
) -> Option<Vec<Ident>>
pub(crate) fn check_for_nested_field_satisfying( &self, span: Span, matches: &impl Fn(&FieldDef, Ty<'tcx>) -> bool, candidate_field: &FieldDef, subst: GenericArgsRef<'tcx>, field_path: Vec<Ident>, mod_id: DefId ) -> Option<Vec<Ident>>
This method is called after we have encountered a missing field error to recursively search for the field
fn check_expr_index( &self, base: &'tcx Expr<'tcx>, idx: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx>, brackets_span: Span ) -> Ty<'tcx>
sourcefn find_and_report_unsatisfied_index_impl(
&self,
base_expr: &Expr<'_>,
base_ty: Ty<'tcx>
) -> Option<(ErrorGuaranteed, Ty<'tcx>, Ty<'tcx>)>
fn find_and_report_unsatisfied_index_impl( &self, base_expr: &Expr<'_>, base_ty: Ty<'tcx> ) -> Option<(ErrorGuaranteed, Ty<'tcx>, Ty<'tcx>)>
Try to match an implementation of Index
against a self type, and report
the unsatisfied predicates that result from confirming this impl.
Given an index expression, sometimes the Self
type shallowly but does not
deeply satisfy an impl predicate. Instead of simply saying that the type
does not support being indexed, we want to point out exactly what nested
predicates cause this to be, so that the user can add them to fix their code.
fn point_at_index_if_possible( &self, errors: &mut Vec<FulfillmentError<'tcx>>, span: Span )
fn check_expr_yield( &self, value: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx>, src: &'tcx YieldSource ) -> Ty<'tcx>
fn check_expr_asm_operand(&self, expr: &'tcx Expr<'tcx>, is_input: bool)
fn check_expr_asm(&self, asm: &'tcx InlineAsm<'tcx>) -> Ty<'tcx>
fn check_offset_of( &self, container: &'tcx Ty<'tcx>, fields: &[Ident], expr: &'tcx Expr<'tcx> ) -> Ty<'tcx>
source§impl<'tcx> FnCtxt<'_, 'tcx>
impl<'tcx> FnCtxt<'_, 'tcx>
sourcepub(crate) fn type_inference_fallback(&self)
pub(crate) fn type_inference_fallback(&self)
Performs type inference fallback, setting FnCtxt::fallback_has_occurred
if fallback has occurred.
fn fallback_types(&self) -> bool
fn fallback_effects(&self) -> bool
fn fallback_if_possible( &self, ty: Ty<'tcx>, diverging_fallback: &UnordMap<Ty<'tcx>, Ty<'tcx>> )
sourcefn calculate_diverging_fallback(
&self,
unsolved_variables: &[Ty<'tcx>]
) -> UnordMap<Ty<'tcx>, Ty<'tcx>>
fn calculate_diverging_fallback( &self, unsolved_variables: &[Ty<'tcx>] ) -> UnordMap<Ty<'tcx>, Ty<'tcx>>
The “diverging fallback” system is rather complicated. This is a result of our need to balance ‘do the right thing’ with backwards compatibility.
“Diverging” type variables are variables created when we
coerce a !
type into an unbound type variable ?X
. If they
never wind up being constrained, the “right and natural” thing
is that ?X
should “fallback” to !
. This means that e.g. an
expression like Some(return)
will ultimately wind up with a
type like Option<!>
(presuming it is not assigned or
constrained to have some other type).
However, the fallback used to be ()
(before the !
type was
added). Moreover, there are cases where the !
type ‘leaks
out’ from dead code into type variables that affect live
code. The most common case is something like this:
match foo() {
22 => Default::default(), // call this type `?D`
_ => return, // return has type `!`
} // call the type of this match `?M`
Here, coercing the type !
into ?M
will create a diverging
type variable ?X
where ?X <: ?M
. We also have that ?D <: ?M
. If ?M
winds up unconstrained, then ?X
will
fallback. If it falls back to !
, then all the type variables
will wind up equal to !
– this includes the type ?D
(since !
doesn’t implement Default
, we wind up a “trait
not implemented” error in code like this). But since the
original fallback was ()
, this code used to compile with ?D = ()
. This is somewhat surprising, since Default::default()
on its own would give an error because the types are
insufficiently constrained.
Our solution to this dilemma is to modify diverging variables
so that they can either fallback to !
(the default) or to
()
(the backwards compatibility case). We decide which
fallback to use based on whether there is a coercion pattern
like this:
?Diverging -> ?V
?NonDiverging -> ?V
?V != ?NonDiverging
Here ?Diverging
represents some diverging type variable and
?NonDiverging
represents some non-diverging type
variable. ?V
can be any type variable (diverging or not), so
long as it is not equal to ?NonDiverging
.
Intuitively, what we are looking for is a case where a
“non-diverging” type variable (like ?M
in our example above)
is coerced into some variable ?V
that would otherwise
fallback to !
. In that case, we make ?V
fallback to !
,
along with anything that would flow into ?V
.
The algorithm we use:
- Identify all variables that are coerced into by a
diverging variable. Do this by iterating over each
diverging, unsolved variable and finding all variables
reachable from there. Call that set
D
. - Walk over all unsolved, non-diverging variables, and find
any variable that has an edge into
D
.
sourcefn create_coercion_graph(&self) -> VecGraph<TyVid>
fn create_coercion_graph(&self) -> VecGraph<TyVid>
Returns a graph whose nodes are (unresolved) inference variables and where
an edge ?A -> ?B
indicates that the variable ?A
is coerced to ?B
.
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
sourcepub(crate) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str)
pub(crate) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str)
Produces warning on the given node, if the current point in the function is unreachable, and there hasn’t been another warning.
sourcepub(crate) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx>
pub(crate) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx>
Resolves type and const variables in ty
if possible. Unlike the infcx
version (resolve_vars_if_possible), this version will
also select obligations if it seems useful, in an effort
to get more type information.
pub(crate) fn record_deferred_call_resolution( &self, closure_def_id: LocalDefId, r: DeferredCallResolution<'tcx> )
pub(crate) fn remove_deferred_call_resolutions( &self, closure_def_id: LocalDefId ) -> Vec<DeferredCallResolution<'tcx>>
pub fn tag(&self) -> String
pub fn local_ty(&self, span: Span, nid: HirId) -> Ty<'tcx>
pub fn write_ty(&self, id: HirId, ty: Ty<'tcx>)
pub fn write_field_index(&self, hir_id: HirId, index: FieldIdx)
pub(crate) fn write_resolution( &self, hir_id: HirId, r: Result<(DefKind, DefId), ErrorGuaranteed> )
pub fn write_method_call(&self, hir_id: HirId, method: MethodCallee<'tcx>)
pub fn write_args(&self, node_id: HirId, args: GenericArgsRef<'tcx>)
sourcepub fn write_user_type_annotation_from_args(
&self,
hir_id: HirId,
def_id: DefId,
args: GenericArgsRef<'tcx>,
user_self_ty: Option<UserSelfTy<'tcx>>
)
pub fn write_user_type_annotation_from_args( &self, hir_id: HirId, def_id: DefId, args: GenericArgsRef<'tcx>, user_self_ty: Option<UserSelfTy<'tcx>> )
Given the args that we just converted from the HIR, try to canonicalize them and store them as user-given substitutions (i.e., substitutions that must be respected by the NLL check).
This should be invoked before any unifications have
occurred, so that annotations like Vec<_>
are preserved
properly.
pub fn write_user_type_annotation( &self, hir_id: HirId, canonical_user_type_annotation: CanonicalUserType<'tcx> )
pub fn apply_adjustments(&self, expr: &Expr<'_>, adj: Vec<Adjustment<'tcx>>)
sourcepub(crate) fn instantiate_bounds(
&self,
span: Span,
def_id: DefId,
args: GenericArgsRef<'tcx>
) -> InstantiatedPredicates<'tcx>
pub(crate) fn instantiate_bounds( &self, span: Span, def_id: DefId, args: GenericArgsRef<'tcx> ) -> InstantiatedPredicates<'tcx>
Instantiates and normalizes the bounds for a given item
pub(crate) fn normalize<T>(&self, span: Span, value: T) -> Twhere T: TypeFoldable<TyCtxt<'tcx>>,
pub fn require_type_meets( &self, ty: Ty<'tcx>, span: Span, code: ObligationCauseCode<'tcx>, def_id: DefId )
pub fn require_type_is_sized( &self, ty: Ty<'tcx>, span: Span, code: ObligationCauseCode<'tcx> )
pub fn require_type_is_sized_deferred( &self, ty: Ty<'tcx>, span: Span, code: ObligationCauseCode<'tcx> )
pub fn register_bound( &self, ty: Ty<'tcx>, def_id: DefId, cause: ObligationCause<'tcx> )
pub fn handle_raw_ty(&self, span: Span, ty: Ty<'tcx>) -> RawTy<'tcx>
pub fn to_ty(&self, ast_t: &Ty<'_>) -> RawTy<'tcx>
pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &Ty<'_>) -> Ty<'tcx>
pub(super) fn user_args_for_adt(ty: RawTy<'tcx>) -> UserArgs<'tcx>
pub fn array_length_to_const(&self, length: &ArrayLen) -> Const<'tcx>
pub fn const_arg_to_const( &self, ast_c: &AnonConst, param_def_id: DefId ) -> Const<'tcx>
fn can_contain_user_lifetime_bounds<T>(t: T) -> boolwhere T: TypeVisitable<TyCtxt<'tcx>>,
pub fn node_ty(&self, id: HirId) -> Ty<'tcx>
pub fn node_ty_opt(&self, id: HirId) -> Option<Ty<'tcx>>
sourcepub fn register_wf_obligation(
&self,
arg: GenericArg<'tcx>,
span: Span,
code: ObligationCauseCode<'tcx>
)
pub fn register_wf_obligation( &self, arg: GenericArg<'tcx>, span: Span, code: ObligationCauseCode<'tcx> )
Registers an obligation for checking later, during regionck, that arg
is well-formed.
sourcepub fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, expr: &Expr<'_>)
pub fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, expr: &Expr<'_>)
Registers obligations that all args
are well-formed.
pub fn field_ty( &self, span: Span, field: &'tcx FieldDef, args: GenericArgsRef<'tcx> ) -> Ty<'tcx>
pub(crate) fn resolve_rvalue_scopes(&self, def_id: DefId)
sourcepub(crate) fn resolve_generator_interiors(&self, def_id: DefId)
pub(crate) fn resolve_generator_interiors(&self, def_id: DefId)
Unify the inference variables corresponding to generator witnesses, and save all the predicates that were stalled on those inference variables.
This process allows to conservatively save all predicates that do depend on the generator
interior types, for later processing by check_generator_obligations
.
We must not attempt to select obligations after this method has run, or risk query cycle ICE.
pub(crate) fn report_ambiguity_errors(&self)
sourcepub(crate) fn select_obligations_where_possible(
&self,
mutate_fulfillment_errors: impl Fn(&mut Vec<FulfillmentError<'tcx>>)
)
pub(crate) fn select_obligations_where_possible( &self, mutate_fulfillment_errors: impl Fn(&mut Vec<FulfillmentError<'tcx>>) )
Select as many obligations as we can at present.
sourcepub(crate) fn make_overloaded_place_return_type(
&self,
method: MethodCallee<'tcx>
) -> TypeAndMut<'tcx>
pub(crate) fn make_overloaded_place_return_type( &self, method: MethodCallee<'tcx> ) -> TypeAndMut<'tcx>
For the overloaded place expressions (*x
, x[3]
), the trait
returns a type of &T
, but the actual type we assign to the
expression is T
. So this function just peels off the return
type by one layer to yield T
.
fn self_type_matches_expected_vid( &self, self_ty: Ty<'tcx>, expected_vid: TyVid ) -> bool
pub(crate) fn obligations_for_self_ty<'b>( &'b self, self_ty: TyVid ) -> impl DoubleEndedIterator<Item = PredicateObligation<'tcx>> + Captures<'tcx> + 'b
pub(crate) fn type_var_is_sized(&self, self_ty: TyVid) -> bool
pub(crate) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>>
sourcepub(crate) fn expected_inputs_for_expected_output(
&self,
call_span: Span,
expected_ret: Expectation<'tcx>,
formal_ret: Ty<'tcx>,
formal_args: &[Ty<'tcx>]
) -> Option<Vec<Ty<'tcx>>>
pub(crate) fn expected_inputs_for_expected_output( &self, call_span: Span, expected_ret: Expectation<'tcx>, formal_ret: Ty<'tcx>, formal_args: &[Ty<'tcx>] ) -> Option<Vec<Ty<'tcx>>>
Unifies the output type with the expected type early, for more coercions and forward type information on the input expressions.
pub(crate) fn resolve_lang_item_path( &self, lang_item: LangItem, span: Span, hir_id: HirId, expr_hir_id: Option<HirId> ) -> (Res, Ty<'tcx>)
sourcepub fn resolve_ty_and_res_fully_qualified_call(
&self,
qpath: &'tcx QPath<'tcx>,
hir_id: HirId,
span: Span
) -> (Res, Option<RawTy<'tcx>>, &'tcx [PathSegment<'tcx>])
pub fn resolve_ty_and_res_fully_qualified_call( &self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, span: Span ) -> (Res, Option<RawTy<'tcx>>, &'tcx [PathSegment<'tcx>])
Resolves an associated value path into a base type and associated constant, or method
resolution. The newly resolved definition is written into type_dependent_defs
.
sourcepub(crate) fn get_node_fn_decl(
&self,
node: Node<'tcx>
) -> Option<(HirId, &'tcx FnDecl<'tcx>, Ident, bool)>
pub(crate) fn get_node_fn_decl( &self, node: Node<'tcx> ) -> Option<(HirId, &'tcx FnDecl<'tcx>, Ident, bool)>
Given a function Node
, return its HirId
and FnDecl
if it exists. Given a closure
that is the child of a function, return that function’s HirId
and FnDecl
instead.
This may seem confusing at first, but this is used in diagnostics for async fn
,
for example, where most of the type checking actually happens within a nested closure,
but we often want access to the parent function’s signature.
Otherwise, return false.
sourcepub fn get_fn_decl(
&self,
blk_id: HirId
) -> Option<(HirId, &'tcx FnDecl<'tcx>, bool)>
pub fn get_fn_decl( &self, blk_id: HirId ) -> Option<(HirId, &'tcx FnDecl<'tcx>, bool)>
Given a HirId
, return the HirId
of the enclosing function, its FnDecl
, and whether a
suggestion can be made, None
otherwise.
pub(crate) fn note_internal_mutation_in_method( &self, err: &mut Diagnostic, expr: &Expr<'_>, expected: Option<Ty<'tcx>>, found: Ty<'tcx> )
pub fn instantiate_value_path( &self, segments: &[PathSegment<'_>], self_ty: Option<RawTy<'tcx>>, res: Res, span: Span, hir_id: HirId ) -> (Ty<'tcx>, Res)
sourcepub(crate) fn add_required_obligations_for_hir(
&self,
span: Span,
def_id: DefId,
args: GenericArgsRef<'tcx>,
hir_id: HirId
)
pub(crate) fn add_required_obligations_for_hir( &self, span: Span, def_id: DefId, args: GenericArgsRef<'tcx>, hir_id: HirId )
Add all the obligations that are required, substituting and normalized appropriately.
fn add_required_obligations_with_code( &self, span: Span, def_id: DefId, args: GenericArgsRef<'tcx>, code: impl Fn(usize, Span) -> ObligationCauseCode<'tcx> )
sourcepub fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx>
pub fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx>
Try to resolve ty
to a structural type, normalizing aliases.
In case there is still ambiguity, the returned type may be an inference
variable. This is different from structurally_resolve_type
which errors
in this case.
sourcepub fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx>
pub fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx>
Resolves ty
by a single level if ty
is a type variable.
When the new solver is enabled, this will also attempt to normalize the type if it’s a projection (note that it will not deeply normalize projections within the type, just the outermost layer of the type).
If no resolution is possible, then an error is reported. Numeric inference variables may be left unresolved.
pub(crate) fn with_breakable_ctxt<F: FnOnce() -> R, R>( &self, id: HirId, ctxt: BreakableCtxt<'tcx>, f: F ) -> (BreakableCtxt<'tcx>, R)
sourcepub(crate) fn probe_instantiate_query_response(
&self,
span: Span,
original_values: &OriginalQueryValues<'tcx>,
query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>
) -> InferResult<'tcx, Ty<'tcx>>
pub(crate) fn probe_instantiate_query_response( &self, span: Span, original_values: &OriginalQueryValues<'tcx>, query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>> ) -> InferResult<'tcx, Ty<'tcx>>
Instantiate a QueryResponse in a probe context, without a good ObligationCause.
sourcepub(crate) fn expr_in_place(&self, expr_id: HirId) -> bool
pub(crate) fn expr_in_place(&self, expr_id: HirId) -> bool
Returns true
if an expression is contained inside the LHS of an assignment expression.
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn adjust_fulfillment_error_for_expr_obligation( &self, error: &mut FulfillmentError<'tcx> ) -> bool
fn point_at_path_if_possible( &self, error: &mut FulfillmentError<'tcx>, def_id: DefId, param: GenericArg<'tcx>, qpath: &QPath<'tcx> ) -> bool
fn point_at_generic_if_possible( &self, error: &mut FulfillmentError<'tcx>, def_id: DefId, param_to_point_at: GenericArg<'tcx>, segment: &PathSegment<'tcx> ) -> bool
fn find_ambiguous_parameter_in<T: TypeVisitable<TyCtxt<'tcx>>>( &self, item_def_id: DefId, t: T ) -> Option<GenericArg<'tcx>>
fn closure_span_overlaps_error( &self, error: &FulfillmentError<'tcx>, span: Span ) -> bool
fn point_at_field_if_possible( &self, def_id: DefId, param_to_point_at: GenericArg<'tcx>, variant_def_id: DefId, expr_fields: &[ExprField<'tcx>] ) -> Option<(&'tcx Expr<'tcx>, Ty<'tcx>)>
sourcefn blame_specific_arg_if_possible(
&self,
error: &mut FulfillmentError<'tcx>,
def_id: DefId,
param_to_point_at: GenericArg<'tcx>,
call_hir_id: HirId,
callee_span: Span,
receiver: Option<&'tcx Expr<'tcx>>,
args: &'tcx [Expr<'tcx>]
) -> bool
fn blame_specific_arg_if_possible( &self, error: &mut FulfillmentError<'tcx>, def_id: DefId, param_to_point_at: GenericArg<'tcx>, call_hir_id: HirId, callee_span: Span, receiver: Option<&'tcx Expr<'tcx>>, args: &'tcx [Expr<'tcx>] ) -> bool
-
blame_specific_*
means that the function will recursively traverse the expression, looking for the most-specific-possible span to blame. -
point_at_*
means that the function will only go “one level”, pointing at the specific expression mentioned.
blame_specific_arg_if_possible
will find the most-specific expression anywhere inside
the provided function call expression, and mark it as responsible for the fulfillment
error.
sourcepub fn blame_specific_expr_if_possible(
&self,
error: &mut FulfillmentError<'tcx>,
expr: &'tcx Expr<'tcx>
)
pub fn blame_specific_expr_if_possible( &self, error: &mut FulfillmentError<'tcx>, expr: &'tcx Expr<'tcx> )
Recursively searches for the most-specific blameable expression. For example, if you have a chain of constraints like:
- want
Vec<i32>: Copy
- because
Option<Vec<i32>>: Copy
needsVec<i32>: Copy
becauseimpl <T: Copy> Copy for Option<T>
- because
(Option<Vec<i32>, bool)
needsOption<Vec<i32>>: Copy
becauseimpl <A: Copy, B: Copy> Copy for (A, B)
then if you pass in(Some(vec![1, 2, 3]), false)
, this helperpoint_at_specific_expr_if_possible
will find the expressionvec![1, 2, 3]
as the “most blameable” reason for this missing constraint.
This function only updates the error span.
fn blame_specific_expr_if_possible_for_obligation_cause_code( &self, obligation_cause_code: &ObligationCauseCode<'tcx>, expr: &'tcx Expr<'tcx> ) -> Result<&'tcx Expr<'tcx>, &'tcx Expr<'tcx>>
sourcefn blame_specific_expr_if_possible_for_derived_predicate_obligation(
&self,
obligation: &ImplDerivedObligationCause<'tcx>,
expr: &'tcx Expr<'tcx>
) -> Result<&'tcx Expr<'tcx>, &'tcx Expr<'tcx>>
fn blame_specific_expr_if_possible_for_derived_predicate_obligation( &self, obligation: &ImplDerivedObligationCause<'tcx>, expr: &'tcx Expr<'tcx> ) -> Result<&'tcx Expr<'tcx>, &'tcx Expr<'tcx>>
We want to achieve the error span in the following example:
struct Burrito<Filling> {
filling: Filling,
}
impl <Filling: Delicious> Delicious for Burrito<Filling> {}
fn eat_delicious_food<Food: Delicious>(_food: Food) {}
fn will_type_error() {
eat_delicious_food(Burrito { filling: Kale });
} // ^--- The trait bound `Kale: Delicious`
// is not satisfied
Without calling this function, the error span will cover the entire argument expression.
Before we do any of this logic, we recursively call point_at_specific_expr_if_possible
on the parent
obligation. Hence we refine the expr
“outwards-in” and bail at the first kind of expression/impl we don’t recognize.
This function returns a Result<&Expr, &Expr>
- either way, it returns the Expr
whose span should be
reported as an error. If it is Ok
, then it means it refined successful. If it is Err
, then it may be
only a partial success - but it cannot be refined even further.
sourcefn blame_specific_part_of_expr_corresponding_to_generic_param(
&self,
param: GenericArg<'tcx>,
expr: &'tcx Expr<'tcx>,
in_ty: GenericArg<'tcx>
) -> Result<&'tcx Expr<'tcx>, &'tcx Expr<'tcx>>
fn blame_specific_part_of_expr_corresponding_to_generic_param( &self, param: GenericArg<'tcx>, expr: &'tcx Expr<'tcx>, in_ty: GenericArg<'tcx> ) -> Result<&'tcx Expr<'tcx>, &'tcx Expr<'tcx>>
Drills into expr
to arrive at the equivalent location of find_generic_param
in in_ty
.
For example, given
- expr:
(Some(vec![1, 2, 3]), false)
- param:
T
- in_ty:
(Option<Vec<T>, bool)
we would drill until we arrive atvec![1, 2, 3]
.
If successful, we return Ok(refined_expr)
. If unsuccessful, we return Err(partially_refined_expr
),
which will go as far as possible. For example, given (foo(), false)
instead, we would drill to
foo()
and then return Err("foo()")
.
This means that you can (and should) use the ?
try operator to chain multiple calls to this
function with different types, since you can only continue drilling the second time if you
succeeded the first time.
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub(crate) fn check_casts(&mut self)
pub(crate) fn check_transmutes(&self)
pub(crate) fn check_asms(&self)
pub(crate) fn check_method_argument_types( &self, sp: Span, expr: &'tcx Expr<'tcx>, method: Result<MethodCallee<'tcx>, ()>, args_no_rcvr: &'tcx [Expr<'tcx>], tuple_arguments: TupleArgumentsFlag, expected: Expectation<'tcx> ) -> Ty<'tcx>
sourcepub(crate) fn check_argument_types(
&self,
call_span: Span,
call_expr: &'tcx Expr<'tcx>,
formal_input_tys: &[Ty<'tcx>],
expected_input_tys: Option<Vec<Ty<'tcx>>>,
provided_args: &'tcx [Expr<'tcx>],
c_variadic: bool,
tuple_arguments: TupleArgumentsFlag,
fn_def_id: Option<DefId>
)
pub(crate) fn check_argument_types( &self, call_span: Span, call_expr: &'tcx Expr<'tcx>, formal_input_tys: &[Ty<'tcx>], expected_input_tys: Option<Vec<Ty<'tcx>>>, provided_args: &'tcx [Expr<'tcx>], c_variadic: bool, tuple_arguments: TupleArgumentsFlag, fn_def_id: Option<DefId> )
Generic function that factors out common logic from function calls, method calls and overloaded operators.
fn report_arg_errors( &self, compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>, formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, provided_args: IndexVec<ProvidedIdx, &'tcx Expr<'tcx>>, c_variadic: bool, err_code: &str, fn_def_id: Option<DefId>, call_span: Span, call_expr: &'tcx Expr<'tcx> )
fn suggest_ptr_null_mut( &self, expected_ty: Ty<'tcx>, provided_ty: Ty<'tcx>, arg: &Expr<'tcx>, err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed> )
pub(crate) fn check_lit( &self, lit: &Lit, expected: Expectation<'tcx> ) -> Ty<'tcx>
pub fn check_struct_path( &self, qpath: &QPath<'_>, hir_id: HirId ) -> Result<(&'tcx VariantDef, Ty<'tcx>), ErrorGuaranteed>
pub fn check_decl_initializer( &self, hir_id: HirId, pat: &'tcx Pat<'tcx>, init: &'tcx Expr<'tcx> ) -> Ty<'tcx>
pub(crate) fn check_decl(&self, decl: Declaration<'tcx>)
sourcepub fn check_decl_local(&self, local: &'tcx Local<'tcx>)
pub fn check_decl_local(&self, local: &'tcx Local<'tcx>)
Type check a let
statement.
pub fn check_stmt(&self, stmt: &'tcx Stmt<'tcx>)
pub fn check_block_no_value(&self, blk: &'tcx Block<'tcx>)
pub(crate) fn check_block_with_expected( &self, blk: &'tcx Block<'tcx>, expected: Expectation<'tcx> ) -> Ty<'tcx>
fn parent_item_span(&self, id: HirId) -> Option<Span>
sourcefn get_parent_fn_decl(
&self,
blk_id: HirId
) -> Option<(&'tcx FnDecl<'tcx>, Ident)>
fn get_parent_fn_decl( &self, blk_id: HirId ) -> Option<(&'tcx FnDecl<'tcx>, Ident)>
Given a function block’s HirId
, returns its FnDecl
if it exists, or None
otherwise.
sourcefn get_expr_coercion_span(&self, expr: &Expr<'_>) -> Span
fn get_expr_coercion_span(&self, expr: &Expr<'_>) -> Span
If expr
is a match
expression that has only one non-!
arm, use that arm’s tail
expression’s Span
, otherwise return expr.span
. This is done to give better errors
when given code like the following:
if false { return 0i32; } else { 1u32 }
// ^^^^ point at this instead of the whole `if` expression
fn overwrite_local_ty_if_err( &self, hir_id: HirId, pat: &'tcx Pat<'tcx>, ty: Ty<'tcx> )
fn finish_resolving_struct_path( &self, qpath: &QPath<'_>, path_span: Span, hir_id: HirId ) -> (Res, RawTy<'tcx>)
sourcepub(super) fn adjust_fulfillment_errors_for_expr_obligation(
&self,
errors: &mut Vec<FulfillmentError<'tcx>>
)
pub(super) fn adjust_fulfillment_errors_for_expr_obligation( &self, errors: &mut Vec<FulfillmentError<'tcx>> )
Given a vector of fulfillment errors, try to adjust the spans of the errors to more accurately point at the cause of the failure.
This applies to calls, methods, and struct expressions. This will also
try to deduplicate errors that are due to the same cause but might
have been created with different ObligationCause
s.
fn label_fn_like( &self, err: &mut Diagnostic, callable_def_id: Option<DefId>, callee_ty: Option<Ty<'tcx>>, expected_idx: Option<usize>, is_method: bool )
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub(crate) fn body_fn_sig(&self) -> Option<FnSig<'tcx>>
pub(crate) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic)
sourcepub fn suggest_mismatched_types_on_tail(
&self,
err: &mut Diagnostic,
expr: &'tcx Expr<'tcx>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
blk_id: HirId
) -> bool
pub fn suggest_mismatched_types_on_tail( &self, err: &mut Diagnostic, expr: &'tcx Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, blk_id: HirId ) -> bool
On implicit return expressions with mismatched types, provides the following suggestions:
- Points out the method’s return type as the reason for the expected type.
- Possible missing semicolon.
- Possible missing return type if the return type is the default, and not
fn main()
.
sourcepub(crate) fn suggest_fn_call(
&self,
err: &mut Diagnostic,
expr: &Expr<'_>,
found: Ty<'tcx>,
can_satisfy: impl FnOnce(Ty<'tcx>) -> bool
) -> bool
pub(crate) fn suggest_fn_call( &self, err: &mut Diagnostic, expr: &Expr<'_>, found: Ty<'tcx>, can_satisfy: impl FnOnce(Ty<'tcx>) -> bool ) -> bool
When encountering an fn-like type, try accessing the output of the type and suggesting calling it if it satisfies a predicate (i.e. if the output has a method or a field):
fn foo(x: usize) -> usize { x }
let x: usize = foo; // suggest calling the `foo` function: `foo(42)`
sourcepub(crate) fn extract_callable_info(
&self,
ty: Ty<'tcx>
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>
pub(crate) fn extract_callable_info( &self, ty: Ty<'tcx> ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>
Extracts information about a callable type for diagnostics. This is a heuristic – it doesn’t necessarily mean that a type is always callable, because the callable type must also be well-formed to be called.
pub fn suggest_two_fn_call( &self, err: &mut Diagnostic, lhs_expr: &'tcx Expr<'tcx>, lhs_ty: Ty<'tcx>, rhs_expr: &'tcx Expr<'tcx>, rhs_ty: Ty<'tcx>, can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool ) -> bool
pub fn suggest_remove_last_method_call( &self, err: &mut Diagnostic, expr: &Expr<'tcx>, expected: Ty<'tcx> ) -> bool
pub fn suggest_deref_ref_or_into( &self, err: &mut Diagnostic, expr: &Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>> ) -> bool
fn deconstruct_option_or_result( &self, found_ty: Ty<'tcx>, expected_ty: Ty<'tcx> ) -> Option<(Ty<'tcx>, Ty<'tcx>, Option<(Ty<'tcx>, Ty<'tcx>)>)>
sourcepub(crate) fn suggest_boxing_when_appropriate(
&self,
err: &mut Diagnostic,
span: Span,
hir_id: HirId,
expected: Ty<'tcx>,
found: Ty<'tcx>
) -> bool
pub(crate) fn suggest_boxing_when_appropriate( &self, err: &mut Diagnostic, span: Span, hir_id: HirId, expected: Ty<'tcx>, found: Ty<'tcx> ) -> bool
When encountering the expected boxed value allocated in the stack, suggest allocating it
in the heap by calling Box::new()
.
sourcepub(crate) fn suggest_no_capture_closure(
&self,
err: &mut Diagnostic,
expected: Ty<'tcx>,
found: Ty<'tcx>
) -> bool
pub(crate) fn suggest_no_capture_closure( &self, err: &mut Diagnostic, expected: Ty<'tcx>, found: Ty<'tcx> ) -> bool
When encountering a closure that captures variables, where a FnPtr is expected, suggest a non-capturing closure
sourcepub(crate) fn suggest_calling_boxed_future_when_appropriate(
&self,
err: &mut Diagnostic,
expr: &Expr<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>
) -> bool
pub(crate) fn suggest_calling_boxed_future_when_appropriate( &self, err: &mut Diagnostic, expr: &Expr<'_>, expected: Ty<'tcx>, found: Ty<'tcx> ) -> bool
When encountering an impl Future
where BoxFuture
is expected, suggest Box::pin
.
sourcepub fn suggest_missing_semicolon(
&self,
err: &mut Diagnostic,
expression: &'tcx Expr<'tcx>,
expected: Ty<'tcx>,
needs_block: bool
)
pub fn suggest_missing_semicolon( &self, err: &mut Diagnostic, expression: &'tcx Expr<'tcx>, expected: Ty<'tcx>, needs_block: bool )
A common error is to forget to add a semicolon at the end of a block, e.g.,
fn foo() {
bar_that_returns_u32()
}
This routine checks if the return expression in a block would make sense on its own as a
statement and the return type has been left as default or has been specified as ()
. If so,
it suggests adding a semicolon.
If the expression is the expression of a closure without block (|| expr
), a
block is needed to be added too (|| { expr; }
). This is denoted by needs_block
.
sourcepub(crate) fn suggest_missing_return_type(
&self,
err: &mut Diagnostic,
fn_decl: &FnDecl<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
can_suggest: bool,
fn_id: HirId
) -> bool
pub(crate) fn suggest_missing_return_type( &self, err: &mut Diagnostic, fn_decl: &FnDecl<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, can_suggest: bool, fn_id: HirId ) -> bool
A possible error is to forget to add a return type that is needed:
fn foo() {
bar_that_returns_u32()
}
This routine checks if the return type is left as default, the method is not part of an
impl
block and that it isn’t the main
method. If so, it suggests setting the return
type.
sourcefn try_suggest_return_impl_trait(
&self,
err: &mut Diagnostic,
expected: Ty<'tcx>,
found: Ty<'tcx>,
fn_id: HirId
)
fn try_suggest_return_impl_trait( &self, err: &mut Diagnostic, expected: Ty<'tcx>, found: Ty<'tcx>, fn_id: HirId )
check whether the return type is a generic type with a trait bound
only suggest this if the generic param is not present in the arguments
if this is true, hint them towards changing the return type to impl Trait
fn cant_name_it<T: Fn() -> u32>() -> T {
|| 3
}
pub(crate) fn suggest_missing_break_or_return_expr( &self, err: &mut Diagnostic, expr: &'tcx Expr<'tcx>, fn_decl: &FnDecl<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, id: HirId, fn_id: HirId )
pub(crate) fn suggest_missing_parentheses( &self, err: &mut Diagnostic, expr: &Expr<'_> ) -> bool
sourcepub(crate) fn suggest_block_to_brackets_peeling_refs(
&self,
diag: &mut Diagnostic,
expr: &Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>
) -> bool
pub(crate) fn suggest_block_to_brackets_peeling_refs( &self, diag: &mut Diagnostic, expr: &Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx> ) -> bool
Given an expression type mismatch, peel any &
expressions until we get to
a block expression, and then suggest replacing the braces with square braces
if it was possibly mistaken array syntax.
pub(crate) fn suggest_clone_for_ref( &self, diag: &mut Diagnostic, expr: &Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx> ) -> bool
pub(crate) fn suggest_copied_cloned_or_as_ref( &self, diag: &mut Diagnostic, expr: &Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx> ) -> bool
pub(crate) fn suggest_into( &self, diag: &mut Diagnostic, expr: &Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx> ) -> bool
sourcepub(crate) fn suggest_option_to_bool(
&self,
diag: &mut Diagnostic,
expr: &Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>
) -> bool
pub(crate) fn suggest_option_to_bool( &self, diag: &mut Diagnostic, expr: &Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx> ) -> bool
When expecting a bool
and finding an Option
, suggests using let Some(..)
or .is_some()
sourcepub(crate) fn suggest_block_to_brackets(
&self,
diag: &mut Diagnostic,
blk: &Block<'_>,
blk_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>
)
pub(crate) fn suggest_block_to_brackets( &self, diag: &mut Diagnostic, blk: &Block<'_>, blk_ty: Ty<'tcx>, expected_ty: Ty<'tcx> )
Suggest wrapping the block in square brackets instead of curly braces
in case the block was mistaken array syntax, e.g. { 1 }
-> [ 1 ]
.
pub(crate) fn suggest_floating_point_literal( &self, err: &mut Diagnostic, expr: &Expr<'_>, expected_ty: Ty<'tcx> ) -> bool
sourcepub(crate) fn suggest_null_ptr_for_literal_zero_given_to_ptr_arg(
&self,
err: &mut Diagnostic,
expr: &Expr<'_>,
expected_ty: Ty<'tcx>
) -> bool
pub(crate) fn suggest_null_ptr_for_literal_zero_given_to_ptr_arg( &self, err: &mut Diagnostic, expr: &Expr<'_>, expected_ty: Ty<'tcx> ) -> bool
Suggest providing std::ptr::null()
or std::ptr::null_mut()
if they
pass in a literal 0 to an raw pointer.
pub(crate) fn suggest_associated_const( &self, err: &mut Diagnostic, expr: &Expr<'_>, expected_ty: Ty<'tcx> ) -> bool
fn is_loop(&self, id: HirId) -> bool
fn is_local_statement(&self, id: HirId) -> bool
sourcepub(crate) fn note_type_is_not_clone(
&self,
diag: &mut Diagnostic,
expected_ty: Ty<'tcx>,
found_ty: Ty<'tcx>,
expr: &Expr<'_>
)
pub(crate) fn note_type_is_not_clone( &self, diag: &mut Diagnostic, expected_ty: Ty<'tcx>, found_ty: Ty<'tcx>, expr: &Expr<'_> )
Suggest that &T
was cloned instead of T
because T
does not implement Clone
,
which is a side-effect of autoref.
sourcefn note_type_is_not_clone_inner_expr<'b>(
&'b self,
expr: &'b Expr<'b>
) -> &'b Expr<'b>
fn note_type_is_not_clone_inner_expr<'b>( &'b self, expr: &'b Expr<'b> ) -> &'b Expr<'b>
Given a type mismatch error caused by &T
being cloned instead of T
, and
the expr
as the source of this type mismatch, try to find the method call
as the source of this error and return that instead. Otherwise, return the
original expression.
sourcepub(crate) fn consider_removing_semicolon(
&self,
blk: &'tcx Block<'tcx>,
expected_ty: Ty<'tcx>,
err: &mut Diagnostic
) -> bool
pub(crate) fn consider_removing_semicolon( &self, blk: &'tcx Block<'tcx>, expected_ty: Ty<'tcx>, err: &mut Diagnostic ) -> bool
A common error is to add an extra semicolon:
fn foo() -> usize {
22;
}
This routine checks if the final statement in a block is an
expression with an explicit semicolon whose type is compatible
with expected_ty
. If so, it suggests removing the semicolon.
pub(crate) fn is_field_suggestable( &self, field: &FieldDef, hir_id: HirId, span: Span ) -> bool
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn new( inh: &'a Inherited<'tcx>, param_env: ParamEnv<'tcx>, body_id: LocalDefId ) -> FnCtxt<'a, 'tcx>
pub fn cause( &self, span: Span, code: ObligationCauseCode<'tcx> ) -> ObligationCause<'tcx>
pub fn misc(&self, span: Span) -> ObligationCause<'tcx>
pub fn sess(&self) -> &Session
sourcepub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx>
pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx>
Creates an TypeErrCtxt
with a reference to the in-progress
TypeckResults
which is used for diagnostics.
Use InferCtxt::err_ctxt
to start one without a TypeckResults
.
pub fn errors_reported_since_creation(&self) -> bool
pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx>
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId)
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn confirm_method( &self, span: Span, self_expr: &'tcx Expr<'tcx>, call_expr: &'tcx Expr<'tcx>, unadjusted_self_ty: Ty<'tcx>, pick: &Pick<'tcx>, segment: &PathSegment<'_> ) -> ConfirmResult<'tcx>
pub fn confirm_method_for_diagnostic( &self, span: Span, self_expr: &'tcx Expr<'tcx>, call_expr: &'tcx Expr<'tcx>, unadjusted_self_ty: Ty<'tcx>, pick: &Pick<'tcx>, segment: &PathSegment<'_> ) -> ConfirmResult<'tcx>
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub(super) fn lint_dot_call_from_2018( &self, self_ty: Ty<'tcx>, segment: &PathSegment<'_>, span: Span, call_expr: &'tcx Expr<'tcx>, self_expr: &'tcx Expr<'tcx>, pick: &Pick<'tcx>, args: &'tcx [Expr<'tcx>] )
pub(super) fn lint_fully_qualified_call_from_2018( &self, span: Span, method_name: Ident, self_ty: Ty<'tcx>, self_ty_span: Span, expr_id: HirId, pick: &Pick<'tcx> )
fn trait_path_or_bare_name( &self, span: Span, expr_hir_id: HirId, trait_def_id: DefId ) -> String
fn trait_path( &self, span: Span, expr_hir_id: HirId, trait_def_id: DefId ) -> Option<String>
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
sourcepub fn probe_for_return_type(
&self,
span: Span,
mode: Mode,
return_type: Ty<'tcx>,
self_ty: Ty<'tcx>,
scope_expr_id: HirId,
candidate_filter: impl Fn(&AssocItem) -> bool
) -> Vec<AssocItem>
pub fn probe_for_return_type( &self, span: Span, mode: Mode, return_type: Ty<'tcx>, self_ty: Ty<'tcx>, scope_expr_id: HirId, candidate_filter: impl Fn(&AssocItem) -> bool ) -> Vec<AssocItem>
This is used to offer suggestions to users. It returns methods that could have been called which have the desired return type. Some effort is made to rule out methods that, if called, would result in an error (basically, the same criteria we would use to decide if a method is a plausible fit for ambiguity purposes).
pub fn probe_for_name( &self, mode: Mode, item_name: Ident, return_type: Option<Ty<'tcx>>, is_suggestion: IsSuggestion, self_ty: Ty<'tcx>, scope_expr_id: HirId, scope: ProbeScope ) -> Result<Pick<'tcx>, MethodError<'tcx>>
pub(crate) fn probe_for_name_many( &self, mode: Mode, item_name: Ident, return_type: Option<Ty<'tcx>>, is_suggestion: IsSuggestion, self_ty: Ty<'tcx>, scope_expr_id: HirId, scope: ProbeScope ) -> Vec<Candidate<'tcx>>
fn probe_op<OP, R>( &'a self, span: Span, mode: Mode, method_name: Option<Ident>, return_type: Option<Ty<'tcx>>, is_suggestion: IsSuggestion, self_ty: Ty<'tcx>, scope_expr_id: HirId, scope: ProbeScope, op: OP ) -> Result<R, MethodError<'tcx>>where OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result<R, MethodError<'tcx>>,
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool
fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool
pub fn report_method_error( &self, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, source: SelfSource<'tcx>, error: MethodError<'tcx>, args: Option<MethodCallComponents<'tcx>>, expected: Expectation<'tcx>, trait_missing_method: bool ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>>
fn suggest_missing_writer( &self, rcvr_ty: Ty<'tcx>, args: MethodCallComponents<'tcx> ) -> DiagnosticBuilder<'_, ErrorGuaranteed>
pub fn report_no_match_method_error( &self, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, source: SelfSource<'tcx>, args: Option<MethodCallComponents<'tcx>>, sugg_span: Span, no_match_data: &mut NoMatchData<'tcx>, expected: Expectation<'tcx>, trait_missing_method: bool ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>>
fn note_candidates_on_method_error( &self, rcvr_ty: Ty<'tcx>, item_name: Ident, args: Option<MethodCallComponents<'tcx>>, span: Span, err: &mut Diagnostic, sources: &mut Vec<CandidateSource>, sugg_span: Option<Span> )
sourcefn suggest_associated_call_syntax(
&self,
err: &mut Diagnostic,
static_candidates: &Vec<CandidateSource>,
rcvr_ty: Ty<'tcx>,
source: SelfSource<'tcx>,
item_name: Ident,
args: Option<MethodCallComponents<'tcx>>,
sugg_span: Span
)
fn suggest_associated_call_syntax( &self, err: &mut Diagnostic, static_candidates: &Vec<CandidateSource>, rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx>, item_name: Ident, args: Option<MethodCallComponents<'tcx>>, sugg_span: Span )
Suggest calling Ty::method
if .method()
isn’t found because the method
doesn’t take a self
receiver.
sourcefn suggest_calling_field_as_fn(
&self,
span: Span,
rcvr_ty: Ty<'tcx>,
expr: &Expr<'_>,
item_name: Ident,
err: &mut Diagnostic
) -> bool
fn suggest_calling_field_as_fn( &self, span: Span, rcvr_ty: Ty<'tcx>, expr: &Expr<'_>, item_name: Ident, err: &mut Diagnostic ) -> bool
Suggest calling a field with a type that implements the Fn*
traits instead of a method with
the same name as the field i.e. (a.my_fn_ptr)(10)
instead of a.my_fn_ptr(10)
.
sourcefn suggest_wrapping_range_with_parens(
&self,
tcx: TyCtxt<'tcx>,
actual: Ty<'tcx>,
source: SelfSource<'tcx>,
span: Span,
item_name: Ident,
ty_str: &str
) -> bool
fn suggest_wrapping_range_with_parens( &self, tcx: TyCtxt<'tcx>, actual: Ty<'tcx>, source: SelfSource<'tcx>, span: Span, item_name: Ident, ty_str: &str ) -> bool
Suggest possible range with adding parentheses, for example:
when encountering 0..1.map(|i| i + 1)
suggest (0..1).map(|i| i + 1)
.
fn suggest_constraining_numerical_ty( &self, tcx: TyCtxt<'tcx>, actual: Ty<'tcx>, source: SelfSource<'_>, span: Span, item_kind: &str, item_name: Ident, ty_str: &str ) -> bool
sourcepub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>])
pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>])
For code rect::area(...)
,
if rect
is a local variable and area
is a valid assoc method for it,
we try to suggest rect.area()
sourcefn suggest_calling_method_on_field(
&self,
err: &mut Diagnostic,
source: SelfSource<'tcx>,
span: Span,
actual: Ty<'tcx>,
item_name: Ident,
return_type: Option<Ty<'tcx>>
)
fn suggest_calling_method_on_field( &self, err: &mut Diagnostic, source: SelfSource<'tcx>, span: Span, actual: Ty<'tcx>, item_name: Ident, return_type: Option<Ty<'tcx>> )
Suggest calling a method on a field i.e. a.field.bar()
instead of a.bar()
fn suggest_unwrapping_inner_self( &self, err: &mut Diagnostic, source: SelfSource<'tcx>, actual: Ty<'tcx>, item_name: Ident )
pub(crate) fn note_unmet_impls_on_type( &self, err: &mut Diagnostic, errors: Vec<FulfillmentError<'tcx>> )
pub fn suggest_derive( &self, err: &mut Diagnostic, unsatisfied_predicates: &[(Predicate<'tcx>, Option<Predicate<'tcx>>, Option<ObligationCause<'tcx>>)] )
fn note_derefed_ty_has_method( &self, err: &mut Diagnostic, self_source: SelfSource<'tcx>, rcvr_ty: Ty<'tcx>, item_name: Ident, expected: Expectation<'tcx> )
sourcefn ty_to_value_string(&self, ty: Ty<'tcx>) -> String
fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String
Print out the type for use in value namespace.
fn suggest_await_before_method( &self, err: &mut Diagnostic, item_name: Ident, ty: Ty<'tcx>, call: &Expr<'_>, span: Span, return_type: Option<Ty<'tcx>> )
fn suggest_use_candidates( &self, err: &mut Diagnostic, msg: String, candidates: Vec<DefId> )
fn suggest_valid_traits( &self, err: &mut Diagnostic, valid_out_of_scope_traits: Vec<DefId> ) -> bool
fn suggest_traits_to_import( &self, err: &mut Diagnostic, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, inputs_len: Option<usize>, source: SelfSource<'tcx>, valid_out_of_scope_traits: Vec<DefId>, unsatisfied_predicates: &[(Predicate<'tcx>, Option<Predicate<'tcx>>, Option<ObligationCause<'tcx>>)], static_candidates: &[CandidateSource], unsatisfied_bounds: bool, return_type: Option<Ty<'tcx>>, trait_missing_method: bool )
sourcepub(crate) fn suggest_else_fn_with_closure(
&self,
err: &mut Diagnostic,
expr: &Expr<'_>,
found: Ty<'tcx>,
expected: Ty<'tcx>
) -> bool
pub(crate) fn suggest_else_fn_with_closure( &self, err: &mut Diagnostic, expr: &Expr<'_>, found: Ty<'tcx>, expected: Ty<'tcx> ) -> bool
issue #102320, for unwrap_or
with closure as argument, suggest unwrap_or_else
FIXME: currently not working for suggesting map_or_else
, see #102408
sourcefn type_derefs_to_local(
&self,
span: Span,
rcvr_ty: Ty<'tcx>,
source: SelfSource<'tcx>
) -> bool
fn type_derefs_to_local( &self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx> ) -> bool
Checks whether there is a local type somewhere in the chain of
autoderefs of rcvr_ty
.
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
sourcepub fn method_exists(
&self,
method_name: Ident,
self_ty: Ty<'tcx>,
call_expr_id: HirId,
return_type: Option<Ty<'tcx>>
) -> bool
pub fn method_exists( &self, method_name: Ident, self_ty: Ty<'tcx>, call_expr_id: HirId, return_type: Option<Ty<'tcx>> ) -> bool
Determines whether the type self_ty
supports a visible method named method_name
or not.
sourcepub(crate) fn suggest_method_call(
&self,
err: &mut Diagnostic,
msg: impl Into<SubdiagnosticMessage> + Debug,
method_name: Ident,
self_ty: Ty<'tcx>,
call_expr: &Expr<'tcx>,
span: Option<Span>
)
pub(crate) fn suggest_method_call( &self, err: &mut Diagnostic, msg: impl Into<SubdiagnosticMessage> + Debug, method_name: Ident, self_ty: Ty<'tcx>, call_expr: &Expr<'tcx>, span: Option<Span> )
Adds a suggestion to call the given method to the provided diagnostic.
sourcepub fn lookup_method(
&self,
self_ty: Ty<'tcx>,
segment: &PathSegment<'_>,
span: Span,
call_expr: &'tcx Expr<'tcx>,
self_expr: &'tcx Expr<'tcx>,
args: &'tcx [Expr<'tcx>]
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>>
pub fn lookup_method( &self, self_ty: Ty<'tcx>, segment: &PathSegment<'_>, span: Span, call_expr: &'tcx Expr<'tcx>, self_expr: &'tcx Expr<'tcx>, args: &'tcx [Expr<'tcx>] ) -> Result<MethodCallee<'tcx>, MethodError<'tcx>>
Performs method lookup. If lookup is successful, it will return the callee
and store an appropriate adjustment for the self-expr. In some cases it may
report an error (e.g., invoking the drop
method).
Arguments
Given a method call like foo.bar::<T1,...Tn>(a, b + 1, ...)
:
self
: the surroundingFnCtxt
(!)self_ty
: the (unadjusted) type of the self expression (foo
)segment
: the name and generic arguments of the method (bar::<T1, ...Tn>
)span
: the span for the method callcall_expr
: the complete method call: (foo.bar::<T1,...Tn>(...)
)self_expr
: the self expression (foo
)args
: the expressions of the arguments (a, b + 1, ...
)
pub fn lookup_method_for_diagnostic( &self, self_ty: Ty<'tcx>, segment: &PathSegment<'_>, span: Span, call_expr: &'tcx Expr<'tcx>, self_expr: &'tcx Expr<'tcx> ) -> Result<MethodCallee<'tcx>, MethodError<'tcx>>
pub fn lookup_probe( &self, method_name: Ident, self_ty: Ty<'tcx>, call_expr: &Expr<'_>, scope: ProbeScope ) -> Result<Pick<'tcx>, MethodError<'tcx>>
pub fn lookup_probe_for_diagnostic( &self, method_name: Ident, self_ty: Ty<'tcx>, call_expr: &Expr<'_>, scope: ProbeScope, return_type: Option<Ty<'tcx>> ) -> Result<Pick<'tcx>, MethodError<'tcx>>
pub(crate) fn obligation_for_method( &self, cause: ObligationCause<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]> ) -> (PredicateObligation<'tcx>, &'tcx List<GenericArg<'tcx>>)
sourcepub(crate) fn lookup_method_in_trait(
&self,
cause: ObligationCause<'tcx>,
m_name: Ident,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
pub(crate) fn lookup_method_in_trait( &self, cause: ObligationCause<'tcx>, m_name: Ident, trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]> ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
lookup_method_in_trait
is used for overloaded operators.
It does a very narrow slice of what the normal probe/confirm path does.
In particular, it doesn’t really do any probing: it simply constructs
an obligation for a particular trait with the given self type and checks
whether that trait is implemented.
fn construct_obligation_for_trait( &self, m_name: Ident, trait_def_id: DefId, obligation: PredicateObligation<'tcx>, args: &'tcx List<GenericArg<'tcx>> ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
sourcepub fn resolve_fully_qualified_call(
&self,
span: Span,
method_name: Ident,
self_ty: Ty<'tcx>,
self_ty_span: Span,
expr_id: HirId
) -> Result<(DefKind, DefId), MethodError<'tcx>>
pub fn resolve_fully_qualified_call( &self, span: Span, method_name: Ident, self_ty: Ty<'tcx>, self_ty_span: Span, expr_id: HirId ) -> Result<(DefKind, DefId), MethodError<'tcx>>
Performs a full-qualified function call (formerly “universal function call”) lookup. If
lookup is successful, it will return the type of definition and the DefId
of the found
function definition.
Arguments
Given a function call like Foo::bar::<T1,...Tn>(...)
:
self
: the surroundingFnCtxt
(!)span
: the span of the call, excluding arguments (Foo::bar::<T1, ...Tn>
)method_name
: the identifier of the function within the container type (bar
)self_ty
: the type to search within (Foo
)self_ty_span
the span for the type being searched within (span ofFoo
)expr_id
: thehir::HirId
of the expression composing the entire call
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
sourcepub fn check_binop_assign(
&self,
expr: &'tcx Expr<'tcx>,
op: BinOp,
lhs: &'tcx Expr<'tcx>,
rhs: &'tcx Expr<'tcx>,
expected: Expectation<'tcx>
) -> Ty<'tcx>
pub fn check_binop_assign( &self, expr: &'tcx Expr<'tcx>, op: BinOp, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>, expected: Expectation<'tcx> ) -> Ty<'tcx>
Checks a a <op>= b
sourcepub fn check_binop(
&self,
expr: &'tcx Expr<'tcx>,
op: BinOp,
lhs_expr: &'tcx Expr<'tcx>,
rhs_expr: &'tcx Expr<'tcx>,
expected: Expectation<'tcx>
) -> Ty<'tcx>
pub fn check_binop( &self, expr: &'tcx Expr<'tcx>, op: BinOp, lhs_expr: &'tcx Expr<'tcx>, rhs_expr: &'tcx Expr<'tcx>, expected: Expectation<'tcx> ) -> Ty<'tcx>
Checks a potentially overloaded binary operator.
fn enforce_builtin_binop_types( &self, lhs_span: Span, lhs_ty: Ty<'tcx>, rhs_span: Span, rhs_ty: Ty<'tcx>, op: BinOp ) -> Ty<'tcx>
fn check_overloaded_binop( &self, expr: &'tcx Expr<'tcx>, lhs_expr: &'tcx Expr<'tcx>, rhs_expr: &'tcx Expr<'tcx>, op: BinOp, is_assign: IsAssign, expected: Expectation<'tcx> ) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)
sourcefn check_str_addition(
&self,
lhs_expr: &'tcx Expr<'tcx>,
rhs_expr: &'tcx Expr<'tcx>,
lhs_ty: Ty<'tcx>,
rhs_ty: Ty<'tcx>,
err: &mut Diagnostic,
is_assign: IsAssign,
op: BinOp
) -> bool
fn check_str_addition( &self, lhs_expr: &'tcx Expr<'tcx>, rhs_expr: &'tcx Expr<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>, err: &mut Diagnostic, is_assign: IsAssign, op: BinOp ) -> bool
Provide actionable suggestions when trying to add two strings with incorrect types,
like &str + &str
, String + String
and &str + &String
.
If this function returns true
it means a note was printed, so we don’t need
to print the normal “implementation of std::ops::Add
might be missing” note
pub fn check_user_unop( &self, ex: &'tcx Expr<'tcx>, operand_ty: Ty<'tcx>, op: UnOp, expected: Expectation<'tcx> ) -> Ty<'tcx>
fn lookup_op_method( &self, lhs_ty: Ty<'tcx>, opt_rhs: Option<(&'tcx Expr<'tcx>, Ty<'tcx>)>, op: Op, expected: Expectation<'tcx> ) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>>
source§impl<'tcx> FnCtxt<'_, 'tcx>
impl<'tcx> FnCtxt<'_, 'tcx>
fn pattern_cause( &self, ti: TopInfo<'tcx>, cause_span: Span ) -> ObligationCause<'tcx>
fn demand_eqtype_pat_diag( &self, cause_span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ti: TopInfo<'tcx> ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>
fn demand_eqtype_pat( &self, cause_span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ti: TopInfo<'tcx> )
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
sourcepub(crate) fn check_pat_top(
&self,
pat: &'tcx Pat<'tcx>,
expected: Ty<'tcx>,
span: Option<Span>,
origin_expr: Option<&'tcx Expr<'tcx>>,
decl_origin: Option<DeclOrigin<'tcx>>
)
pub(crate) fn check_pat_top( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, span: Option<Span>, origin_expr: Option<&'tcx Expr<'tcx>>, decl_origin: Option<DeclOrigin<'tcx>> )
Type check the given top level pattern against the expected
type.
If a Some(span)
is provided and origin_expr
holds,
then the span
represents the scrutinee’s span.
The scrutinee is found in e.g. match scrutinee { ... }
and let pat = scrutinee;
.
Otherwise, Some(span)
represents the span of a type expression
which originated the expected
type.
sourcefn check_pat(
&self,
pat: &'tcx Pat<'tcx>,
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx, '_>
)
fn check_pat( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_> )
Type check the given pat
against the expected
type
with the provided def_bm
(default binding mode).
Outside of this module, check_pat_top
should always be used.
Conversely, inside this module, check_pat_top
should never be used.
sourcefn calc_default_binding_mode(
&self,
pat: &'tcx Pat<'tcx>,
expected: Ty<'tcx>,
def_bm: BindingMode,
adjust_mode: AdjustMode
) -> (Ty<'tcx>, BindingMode)
fn calc_default_binding_mode( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_bm: BindingMode, adjust_mode: AdjustMode ) -> (Ty<'tcx>, BindingMode)
Compute the new expected type and default binding mode from the old ones as well as the pattern form we are currently checking.
sourcefn calc_adjust_mode(
&self,
pat: &'tcx Pat<'tcx>,
opt_path_res: Option<Res>
) -> AdjustMode
fn calc_adjust_mode( &self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res> ) -> AdjustMode
How should the binding mode and expected type be adjusted?
When the pattern is a path pattern, opt_path_res
must be Some(res)
.
sourcefn peel_off_references(
&self,
pat: &'tcx Pat<'tcx>,
expected: Ty<'tcx>,
def_bm: BindingMode
) -> (Ty<'tcx>, BindingMode)
fn peel_off_references( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_bm: BindingMode ) -> (Ty<'tcx>, BindingMode)
Peel off as many immediately nested & mut?
from the expected type as possible
and return the new expected type and binding default binding mode.
The adjustments vector, if non-empty is stored in a table.
fn check_pat_lit( &self, span: Span, lt: &Expr<'tcx>, expected: Ty<'tcx>, ti: TopInfo<'tcx> ) -> Ty<'tcx>
fn check_pat_range( &self, span: Span, lhs: Option<&'tcx Expr<'tcx>>, rhs: Option<&'tcx Expr<'tcx>>, expected: Ty<'tcx>, ti: TopInfo<'tcx> ) -> Ty<'tcx>
fn endpoint_has_type(&self, err: &mut Diagnostic, span: Span, ty: Ty<'_>)
fn emit_err_pat_range( &self, span: Span, lhs: Option<(bool, Ty<'tcx>, Span)>, rhs: Option<(bool, Ty<'tcx>, Span)> ) -> ErrorGuaranteed
fn check_pat_ident( &self, pat: &'tcx Pat<'tcx>, ba: BindingAnnotation, var_id: HirId, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_> ) -> Ty<'tcx>
sourcefn check_binding_alt_eq_ty(
&self,
ba: BindingAnnotation,
span: Span,
var_id: HirId,
ty: Ty<'tcx>,
ti: TopInfo<'tcx>
)
fn check_binding_alt_eq_ty( &self, ba: BindingAnnotation, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx> )
When a variable is bound several times in a PatKind::Or
, it’ll resolve all of the
subsequent bindings of the same name to the first usage. Verify that all of these
bindings have the same type by comparing them all against the type of that first pat.
fn suggest_adding_missing_ref_or_removing_ref( &self, err: &mut Diagnostic, span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ba: BindingAnnotation )
fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>)
pub fn check_dereferenceable( &self, span: Span, expected: Ty<'tcx>, inner: &Pat<'_> ) -> Result<(), ErrorGuaranteed>
fn check_pat_struct( &self, pat: &'tcx Pat<'tcx>, qpath: &QPath<'_>, fields: &'tcx [PatField<'tcx>], has_rest_pat: bool, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_> ) -> Ty<'tcx>
fn check_pat_path( &self, pat: &Pat<'tcx>, qpath: &QPath<'_>, path_resolution: (Res, Option<RawTy<'tcx>>, &'tcx [PathSegment<'tcx>]), expected: Ty<'tcx>, ti: TopInfo<'tcx> ) -> Ty<'tcx>
fn maybe_suggest_range_literal( &self, e: &mut Diagnostic, opt_def_id: Option<DefId>, ident: Ident ) -> bool
fn emit_bad_pat_path( &self, e: DiagnosticBuilder<'_, ErrorGuaranteed>, pat: &Pat<'tcx>, res: Res, pat_res: Res, pat_ty: Ty<'tcx>, segments: &'tcx [PathSegment<'tcx>] )
fn check_pat_tuple_struct( &self, pat: &'tcx Pat<'tcx>, qpath: &'tcx QPath<'tcx>, subpats: &'tcx [Pat<'tcx>], ddpos: DotDotPos, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_> ) -> Ty<'tcx>
fn e0023( &self, pat_span: Span, res: Res, qpath: &QPath<'_>, subpats: &'tcx [Pat<'tcx>], fields: &'tcx [FieldDef], expected: Ty<'tcx>, had_err: bool ) -> ErrorGuaranteed
fn check_pat_tuple( &self, span: Span, elements: &'tcx [Pat<'tcx>], ddpos: DotDotPos, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_> ) -> Ty<'tcx>
fn check_struct_pat_fields( &self, adt_ty: Ty<'tcx>, pat: &'tcx Pat<'tcx>, variant: &'tcx VariantDef, fields: &'tcx [PatField<'tcx>], has_rest_pat: bool, pat_info: PatInfo<'tcx, '_> ) -> bool
fn error_tuple_variant_index_shorthand( &self, variant: &VariantDef, pat: &Pat<'_>, fields: &[PatField<'_>] ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>>
fn error_foreign_non_exhaustive_spat( &self, pat: &Pat<'_>, descr: &str, no_fields: bool )
fn error_field_already_bound( &self, span: Span, ident: Ident, other_field: Span ) -> ErrorGuaranteed
fn error_inexistent_fields( &self, kind_name: &str, inexistent_fields: &[&PatField<'tcx>], unmentioned_fields: &mut Vec<(&'tcx FieldDef, Ident)>, pat: &'tcx Pat<'tcx>, variant: &VariantDef, args: &'tcx List<GenericArg<'tcx>> ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
fn error_tuple_variant_as_struct_pat( &self, pat: &Pat<'_>, fields: &'tcx [PatField<'tcx>], variant: &VariantDef ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>
fn get_suggested_tuple_struct_pattern( &self, fields: &[PatField<'_>], variant: &VariantDef ) -> String
sourcefn error_no_accessible_fields(
&self,
pat: &Pat<'_>,
fields: &'tcx [PatField<'tcx>]
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
fn error_no_accessible_fields( &self, pat: &Pat<'_>, fields: &'tcx [PatField<'tcx>] ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
Returns a diagnostic reporting a struct pattern which is missing an ..
due to
inaccessible fields.
error: pattern requires `..` due to inaccessible fields
--> src/main.rs:10:9
|
LL | let foo::Foo {} = foo::Foo::default();
| ^^^^^^^^^^^
|
help: add a `..`
|
LL | let foo::Foo { .. } = foo::Foo::default();
| ^^^^^^
sourcefn lint_non_exhaustive_omitted_patterns(
&self,
pat: &Pat<'_>,
unmentioned_fields: &[(&FieldDef, Ident)],
ty: Ty<'tcx>
)
fn lint_non_exhaustive_omitted_patterns( &self, pat: &Pat<'_>, unmentioned_fields: &[(&FieldDef, Ident)], ty: Ty<'tcx> )
Report that a pattern for a #[non_exhaustive]
struct marked with non_exhaustive_omitted_patterns
is not exhaustive enough.
Nb: the partner lint for enums lives in compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
.
sourcefn error_unmentioned_fields(
&self,
pat: &Pat<'_>,
unmentioned_fields: &[(&FieldDef, Ident)],
have_inaccessible_fields: bool,
fields: &'tcx [PatField<'tcx>]
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
fn error_unmentioned_fields( &self, pat: &Pat<'_>, unmentioned_fields: &[(&FieldDef, Ident)], have_inaccessible_fields: bool, fields: &'tcx [PatField<'tcx>] ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
Returns a diagnostic reporting a struct pattern which does not mention some fields.
error[E0027]: pattern does not mention field `bar`
--> src/main.rs:15:9
|
LL | let foo::Foo {} = foo::Foo::new();
| ^^^^^^^^^^^ missing field `bar`
fn check_pat_box( &self, span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_> ) -> Ty<'tcx>
fn check_pat_ref( &self, pat: &'tcx Pat<'tcx>, inner: &'tcx Pat<'tcx>, mutbl: Mutability, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_> ) -> Ty<'tcx>
sourcefn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx>
fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx>
Create a reference type with a fresh region variable.
fn try_resolve_slice_ty_to_array_ty( &self, before: &'tcx [Pat<'tcx>], slice: Option<&'tcx Pat<'tcx>>, span: Span ) -> Option<Ty<'tcx>>
sourcefn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool
fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool
Used to determines whether we can infer the expected type in the slice pattern to be of type array. This is only possible if we’re in an irrefutable pattern. If we were to allow this in refutable patterns we wouldn’t e.g. report ambiguity in the following situation:
struct Zeroes;
const ARR: [usize; 2] = [0; 2];
const ARR2: [usize; 2] = [2; 2];
impl Into<&'static [usize; 2]> for Zeroes {
fn into(self) -> &'static [usize; 2] {
&ARR
}
}
impl Into<&'static [usize]> for Zeroes {
fn into(self) -> &'static [usize] {
&ARR2
}
}
fn main() {
let &[a, b]: &[usize] = Zeroes.into() else {
..
};
}
If we’re in an irrefutable pattern we prefer the array impl candidate given that the slice impl candidate would be be rejected anyway (if no ambiguity existed).
sourcefn check_pat_slice(
&self,
span: Span,
before: &'tcx [Pat<'tcx>],
slice: Option<&'tcx Pat<'tcx>>,
after: &'tcx [Pat<'tcx>],
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx, '_>
) -> Ty<'tcx>
fn check_pat_slice( &self, span: Span, before: &'tcx [Pat<'tcx>], slice: Option<&'tcx Pat<'tcx>>, after: &'tcx [Pat<'tcx>], expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_> ) -> Ty<'tcx>
Type check a slice pattern.
Syntactically, these look like [pat_0, ..., pat_n]
.
Semantically, we are type checking a pattern with structure:
[before_0, ..., before_n, (slice, after_0, ... after_n)?]
The type of slice
, if it is present, depends on the expected
type.
If slice
is missing, then so is after_i
.
If slice
is present, it can still represent 0 elements.
sourcefn check_array_pat_len(
&self,
span: Span,
element_ty: Ty<'tcx>,
arr_ty: Ty<'tcx>,
slice: Option<&'tcx Pat<'tcx>>,
len: Const<'tcx>,
min_len: u64
) -> (Option<Ty<'tcx>>, Ty<'tcx>)
fn check_array_pat_len( &self, span: Span, element_ty: Ty<'tcx>, arr_ty: Ty<'tcx>, slice: Option<&'tcx Pat<'tcx>>, len: Const<'tcx>, min_len: u64 ) -> (Option<Ty<'tcx>>, Ty<'tcx>)
Type check the length of an array pattern.
Returns both the type of the variable length pattern (or None
), and the potentially
inferred array type. We only return None
for the slice type if slice.is_none()
.
fn error_scrutinee_inconsistent_length( &self, span: Span, min_len: u64, size: u64 ) -> ErrorGuaranteed
fn error_scrutinee_with_rest_inconsistent_length( &self, span: Span, min_len: u64, size: u64 ) -> ErrorGuaranteed
fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed
fn error_expected_array_or_slice( &self, span: Span, expected_ty: Ty<'tcx>, ti: TopInfo<'tcx> ) -> ErrorGuaranteed
fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>)
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
sourcepub(crate) fn lookup_derefing(
&self,
expr: &Expr<'_>,
oprnd_expr: &'tcx Expr<'tcx>,
oprnd_ty: Ty<'tcx>
) -> Option<Ty<'tcx>>
pub(crate) fn lookup_derefing( &self, expr: &Expr<'_>, oprnd_expr: &'tcx Expr<'tcx>, oprnd_ty: Ty<'tcx> ) -> Option<Ty<'tcx>>
Type-check *oprnd_expr
with oprnd_expr
type-checked already.
sourcepub(crate) fn lookup_indexing(
&self,
expr: &Expr<'_>,
base_expr: &'tcx Expr<'tcx>,
base_ty: Ty<'tcx>,
index_expr: &'tcx Expr<'tcx>,
idx_ty: Ty<'tcx>
) -> Option<(Ty<'tcx>, Ty<'tcx>)>
pub(crate) fn lookup_indexing( &self, expr: &Expr<'_>, base_expr: &'tcx Expr<'tcx>, base_ty: Ty<'tcx>, index_expr: &'tcx Expr<'tcx>, idx_ty: Ty<'tcx> ) -> Option<(Ty<'tcx>, Ty<'tcx>)>
Type-check *base_expr[index_expr]
with base_expr
and index_expr
type-checked already.
fn negative_index( &self, ty: Ty<'tcx>, span: Span, base_expr: &Expr<'_> ) -> Option<(Ty<'tcx>, Ty<'tcx>)>
sourcefn try_index_step(
&self,
expr: &Expr<'_>,
base_expr: &Expr<'_>,
autoderef: &Autoderef<'a, 'tcx>,
index_ty: Ty<'tcx>,
index_expr: &Expr<'_>
) -> Option<(Ty<'tcx>, Ty<'tcx>)>
fn try_index_step( &self, expr: &Expr<'_>, base_expr: &Expr<'_>, autoderef: &Autoderef<'a, 'tcx>, index_ty: Ty<'tcx>, index_expr: &Expr<'_> ) -> Option<(Ty<'tcx>, Ty<'tcx>)>
To type-check base_expr[index_expr]
, we progressively autoderef
(and otherwise adjust) base_expr
, looking for a type which either
supports builtin indexing or overloaded indexing.
This loop implements one step in that search; the autoderef loop
is implemented by lookup_indexing
.
sourcepub(crate) fn try_overloaded_place_op(
&self,
span: Span,
base_ty: Ty<'tcx>,
arg_tys: &[Ty<'tcx>],
op: PlaceOp
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
pub(crate) fn try_overloaded_place_op( &self, span: Span, base_ty: Ty<'tcx>, arg_tys: &[Ty<'tcx>], op: PlaceOp ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
Try to resolve an overloaded place op. We only deal with the immutable
variant here (Deref/Index). In some contexts we would need the mutable
variant (DerefMut/IndexMut); those would be later converted by
convert_place_derefs_to_mutable
.
fn try_mutable_overloaded_place_op( &self, span: Span, base_ty: Ty<'tcx>, arg_tys: &[Ty<'tcx>], op: PlaceOp ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
sourcepub fn convert_place_derefs_to_mutable(&self, expr: &Expr<'_>)
pub fn convert_place_derefs_to_mutable(&self, expr: &Expr<'_>)
Convert auto-derefs, indices, etc of an expression from Deref
and Index
into DerefMut
and IndexMut
respectively.
This is a second pass of typechecking derefs/indices. We need this because we do not always know whether a place needs to be mutable or not in the first pass. This happens whether there is an implicit mutable reborrow, e.g. when the type is used as the receiver of a method call.
fn convert_place_op_to_mutable( &self, op: PlaceOp, expr: &Expr<'_>, base_expr: &Expr<'_> )
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
sourcefn analyze_closure(
&self,
closure_hir_id: HirId,
span: Span,
body_id: BodyId,
body: &'tcx Body<'tcx>,
capture_clause: CaptureBy
)
fn analyze_closure( &self, closure_hir_id: HirId, span: Span, body_id: BodyId, body: &'tcx Body<'tcx>, capture_clause: CaptureBy )
Analysis starting point.
fn final_upvar_tys(&self, closure_id: LocalDefId) -> Vec<Ty<'tcx>>
sourcefn process_collected_capture_information(
&self,
capture_clause: CaptureBy,
capture_information: Vec<(Place<'tcx>, CaptureInfo)>
) -> (Vec<(Place<'tcx>, CaptureInfo)>, ClosureKind, Option<(Span, Place<'tcx>)>)
fn process_collected_capture_information( &self, capture_clause: CaptureBy, capture_information: Vec<(Place<'tcx>, CaptureInfo)> ) -> (Vec<(Place<'tcx>, CaptureInfo)>, ClosureKind, Option<(Span, Place<'tcx>)>)
Adjusts the closure capture information to ensure that the operations aren’t unsafe, and that the path can be captured with required capture kind (depending on use in closure, move closure etc.)
Returns the set of adjusted information along with the inferred closure kind and span associated with the closure kind inference.
Note that we always infer a minimal kind, even if we don’t always use that in the final result (i.e., sometimes we’ve taken the closure kind from the expectations instead, and for generators we don’t even implement the closure traits really).
If we inferred that the closure needs to be FnMut/FnOnce, last element of the returned tuple
contains a Some()
with the Place
that caused us to do so.
sourcefn compute_min_captures(
&self,
closure_def_id: LocalDefId,
capture_information: Vec<(Place<'tcx>, CaptureInfo)>,
closure_span: Span
)
fn compute_min_captures( &self, closure_def_id: LocalDefId, capture_information: Vec<(Place<'tcx>, CaptureInfo)>, closure_span: Span )
Analyzes the information collected by InferBorrowKind
to compute the min number of
Places (and corresponding capture kind) that we need to keep track of to support all
the required captured paths.
Note: If this function is called multiple times for the same closure, it will update the existing min_capture map that is stored in TypeckResults.
Eg:
#[derive(Debug)]
struct Point { x: i32, y: i32 }
let s = String::from("s"); // hir_id_s
let mut p = Point { x: 2, y: -2 }; // his_id_p
let c = || {
println!("{s:?}"); // L1
p.x += 10; // L2
println!("{}" , p.y); // L3
println!("{p:?}"); // L4
drop(s); // L5
};
and let hir_id_L1..5 be the expressions pointing to use of a captured variable on the lines L1..5 respectively.
InferBorrowKind results in a structure like this:
{
Place(base: hir_id_s, projections: [], ....) -> {
capture_kind_expr: hir_id_L5,
path_expr_id: hir_id_L5,
capture_kind: ByValue
},
Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> {
capture_kind_expr: hir_id_L2,
path_expr_id: hir_id_L2,
capture_kind: ByValue
},
Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> {
capture_kind_expr: hir_id_L3,
path_expr_id: hir_id_L3,
capture_kind: ByValue
},
Place(base: hir_id_p, projections: [], ...) -> {
capture_kind_expr: hir_id_L4,
path_expr_id: hir_id_L4,
capture_kind: ByValue
},
}
After the min capture analysis, we get:
{
hir_id_s -> [
Place(base: hir_id_s, projections: [], ....) -> {
capture_kind_expr: hir_id_L5,
path_expr_id: hir_id_L5,
capture_kind: ByValue
},
],
hir_id_p -> [
Place(base: hir_id_p, projections: [], ...) -> {
capture_kind_expr: hir_id_L2,
path_expr_id: hir_id_L4,
capture_kind: ByValue
},
],
}
sourcefn perform_2229_migration_analysis(
&self,
closure_def_id: LocalDefId,
body_id: BodyId,
capture_clause: CaptureBy,
span: Span
)
fn perform_2229_migration_analysis( &self, closure_def_id: LocalDefId, body_id: BodyId, capture_clause: CaptureBy, span: Span )
Perform the migration analysis for RFC 2229, and emit lint
disjoint_capture_drop_reorder
if needed.
sourcefn compute_2229_migrations_reasons(
&self,
auto_trait_reasons: UnordSet<&'static str>,
drop_order: bool
) -> MigrationWarningReason
fn compute_2229_migrations_reasons( &self, auto_trait_reasons: UnordSet<&'static str>, drop_order: bool ) -> MigrationWarningReason
Combines all the reasons for 2229 migrations
sourcefn compute_2229_migrations_for_trait(
&self,
min_captures: Option<&RootVariableMinCaptureList<'tcx>>,
var_hir_id: HirId,
closure_clause: CaptureBy
) -> Option<FxIndexMap<UpvarMigrationInfo, UnordSet<&'static str>>>
fn compute_2229_migrations_for_trait( &self, min_captures: Option<&RootVariableMinCaptureList<'tcx>>, var_hir_id: HirId, closure_clause: CaptureBy ) -> Option<FxIndexMap<UpvarMigrationInfo, UnordSet<&'static str>>>
Figures out the list of root variables (and their types) that aren’t completely
captured by the closure when capture_disjoint_fields
is enabled and auto-traits
differ between the root variable and the captured paths.
Returns a tuple containing a HashMap of CapturesInfo that maps to a HashSet of trait names if migration is needed for traits for the provided var_hir_id, otherwise returns None
sourcefn compute_2229_migrations_for_drop(
&self,
closure_def_id: LocalDefId,
closure_span: Span,
min_captures: Option<&RootVariableMinCaptureList<'tcx>>,
closure_clause: CaptureBy,
var_hir_id: HirId
) -> Option<FxIndexSet<UpvarMigrationInfo>>
fn compute_2229_migrations_for_drop( &self, closure_def_id: LocalDefId, closure_span: Span, min_captures: Option<&RootVariableMinCaptureList<'tcx>>, closure_clause: CaptureBy, var_hir_id: HirId ) -> Option<FxIndexSet<UpvarMigrationInfo>>
Figures out the list of root variables (and their types) that aren’t completely
captured by the closure when capture_disjoint_fields
is enabled and drop order of
some path starting at that root variable might be affected.
The output list would include a root variable if:
- It would have been moved into the closure when
capture_disjoint_fields
wasn’t enabled, and - It wasn’t completely captured by the closure, and
- One of the paths starting at this root variable, that is not captured needs Drop.
This function only returns a HashSet of CapturesInfo for significant drops. If there are no significant drops than None is returned
sourcefn compute_2229_migrations(
&self,
closure_def_id: LocalDefId,
closure_span: Span,
closure_clause: CaptureBy,
min_captures: Option<&RootVariableMinCaptureList<'tcx>>
) -> (Vec<NeededMigration>, MigrationWarningReason)
fn compute_2229_migrations( &self, closure_def_id: LocalDefId, closure_span: Span, closure_clause: CaptureBy, min_captures: Option<&RootVariableMinCaptureList<'tcx>> ) -> (Vec<NeededMigration>, MigrationWarningReason)
Figures out the list of root variables (and their types) that aren’t completely
captured by the closure when capture_disjoint_fields
is enabled and either drop
order of some path starting at that root variable might be affected or auto-traits
differ between the root variable and the captured paths.
The output list would include a root variable if:
- It would have been moved into the closure when
capture_disjoint_fields
wasn’t enabled, and - It wasn’t completely captured by the closure, and
- One of the paths starting at this root variable, that is not captured needs Drop or
- One of the paths captured does not implement all the auto-traits its root variable implements.
Returns a tuple containing a vector of MigrationDiagnosticInfo, as well as a String containing the reason why root variables whose HirId is contained in the vector should be captured
sourcefn has_significant_drop_outside_of_captures(
&self,
closure_def_id: LocalDefId,
closure_span: Span,
base_path_ty: Ty<'tcx>,
captured_by_move_projs: Vec<&[Projection<'tcx>]>
) -> bool
fn has_significant_drop_outside_of_captures( &self, closure_def_id: LocalDefId, closure_span: Span, base_path_ty: Ty<'tcx>, captured_by_move_projs: Vec<&[Projection<'tcx>]> ) -> bool
This is a helper function to compute_2229_migrations_precise_pass
. Provided the type
of a root variable and a list of captured paths starting at this root variable (expressed
using list of Projection
slices), it returns true if there is a path that is not
captured starting at this root variable that implements Drop.
The way this function works is at a given call it looks at type base_path_ty
of some base
path say P and then list of projection slices which represent the different captures moved
into the closure starting off of P.
This will make more sense with an example:
struct FancyInteger(i32); // This implements Drop
struct Point { x: FancyInteger, y: FancyInteger }
struct Color;
struct Wrapper { p: Point, c: Color }
fn f(w: Wrapper) {
let c = || {
// Closure captures w.p.x and w.c by move.
};
c();
}
If capture_disjoint_fields
wasn’t enabled the closure would’ve moved w
instead of the
precise paths. If we look closely w.p.y
isn’t captured which implements Drop and
therefore Drop ordering would change and we want this function to return true.
Call stack to figure out if we need to migrate for w
would look as follows:
Our initial base path is just w
, and the paths captured from it are w[p, x]
and
w[c]
.
Notation:
- Ty(place): Type of place
(a, b)
: Represents the function parametersbase_path_ty
andcaptured_by_move_projs
respectively.
(Ty(w), [ &[p, x], &[c] ])
// |
// ----------------------------
// | |
// v v
(Ty(w.p), [ &[x] ]) (Ty(w.c), [ &[] ]) // I(1)
// | |
// v v
(Ty(w.p), [ &[x] ]) false
// |
// |
// -------------------------------
// | |
// v v
(Ty((w.p).x), [ &[] ]) (Ty((w.p).y), []) // IMP 2
// | |
// v v
false NeedsSignificantDrop(Ty(w.p.y))
// |
// v
true
IMP 1 (Ty(w.c), [ &[] ])
: Notice the single empty slice inside captured_projs
.
This implies that the w.c
is completely captured by the closure.
Since drop for this path will be called when the closure is
dropped we don’t need to migrate for it.
IMP 2 (Ty((w.p).y), [])
: Notice that captured_projs
is empty. This implies that this
path wasn’t captured by the closure. Also note that even
though we didn’t capture this path, the function visits it,
which is kind of the point of this function. We then return
if the type of w.p.y
implements Drop, which in this case is
true.
Consider another example:
struct X;
impl Drop for X {}
struct Y(X);
impl Drop for Y {}
fn foo() {
let y = Y(X);
let c = || move(y.0);
}
Note that y.0
is captured by the closure. When this function is called for y
, it will
return true, because even though all paths starting at y
are captured, y
itself
implements Drop which will be affected since y
isn’t completely captured.
fn init_capture_kind_for_place( &self, place: &Place<'tcx>, capture_clause: CaptureBy ) -> UpvarCapture
fn place_for_root_variable( &self, closure_def_id: LocalDefId, var_hir_id: HirId ) -> Place<'tcx>
fn should_log_capture_analysis(&self, closure_def_id: LocalDefId) -> bool
fn log_capture_analysis_first_pass( &self, closure_def_id: LocalDefId, capture_information: &Vec<(Place<'tcx>, CaptureInfo)>, closure_span: Span )
fn log_closure_min_capture_info( &self, closure_def_id: LocalDefId, closure_span: Span )
sourcefn determine_capture_mutability(
&self,
typeck_results: &'a TypeckResults<'tcx>,
place: &Place<'tcx>
) -> Mutability
fn determine_capture_mutability( &self, typeck_results: &'a TypeckResults<'tcx>, place: &Place<'tcx> ) -> Mutability
A captured place is mutable if
- Projections don’t include a Deref of an immut-borrow, and
- PlaceBase is mut or projections include a Deref of a mut-borrow.
source§impl<'a, 'tcx> FnCtxt<'a, 'tcx>
impl<'a, 'tcx> FnCtxt<'a, 'tcx>
pub fn resolve_type_vars_in_body( &self, body: &'tcx Body<'tcx> ) -> &'tcx TypeckResults<'tcx>
Methods from Deref<Target = Inherited<'tcx>>§
pub(crate) fn register_predicate(&self, obligation: PredicateObligation<'tcx>)
pub(crate) fn register_predicates<I>(&self, obligations: I)where I: IntoIterator<Item = PredicateObligation<'tcx>>,
pub(crate) fn register_infer_ok_obligations<T>( &self, infer_ok: InferOk<'tcx, T> ) -> T
pub fn update_infer_var_info(&self, obligation: &PredicateObligation<'tcx>)
Trait Implementations§
source§impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx>
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx>
fn tcx<'b>(&'b self) -> TyCtxt<'tcx>
fn item_def_id(&self) -> DefId
source§fn get_type_parameter_bounds(
&self,
_: Span,
def_id: LocalDefId,
_: Ident
) -> GenericPredicates<'tcx>
fn get_type_parameter_bounds( &self, _: Span, def_id: LocalDefId, _: Ident ) -> GenericPredicates<'tcx>
X: Foo<T>
, where X
is a type parameter X
with the given id def_id
and T
matches assoc_name
. This is a subset of the full set of
predicates. Read moresource§fn re_infer(
&self,
def: Option<&GenericParamDef>,
span: Span
) -> Option<Region<'tcx>>
fn re_infer( &self, def: Option<&GenericParamDef>, span: Span ) -> Option<Region<'tcx>>
source§fn allow_ty_infer(&self) -> bool
fn allow_ty_infer(&self) -> bool
true
if _
is allowed in type signatures in the current context.source§fn ty_infer(&self, param: Option<&GenericParamDef>, span: Span) -> Ty<'tcx>
fn ty_infer(&self, param: Option<&GenericParamDef>, span: Span) -> Ty<'tcx>
source§fn ct_infer(
&self,
ty: Ty<'tcx>,
param: Option<&GenericParamDef>,
span: Span
) -> Const<'tcx>
fn ct_infer( &self, ty: Ty<'tcx>, param: Option<&GenericParamDef>, span: Span ) -> Const<'tcx>
source§fn projected_ty_from_poly_trait_ref(
&self,
span: Span,
item_def_id: DefId,
item_segment: &PathSegment<'_>,
poly_trait_ref: PolyTraitRef<'tcx>
) -> Ty<'tcx>
fn projected_ty_from_poly_trait_ref( &self, span: Span, item_def_id: DefId, item_segment: &PathSegment<'_>, poly_trait_ref: PolyTraitRef<'tcx> ) -> Ty<'tcx>
source§fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<AdtDef<'tcx>>
fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<AdtDef<'tcx>>
AdtDef
if ty
is an ADT.
Note that ty
might be a projection type that needs normalization.
This used to get the enum variants in scope of the type.
For example, Self::A
could refer to an associated type
or to an enum variant depending on the result of this function.source§fn set_tainted_by_errors(&self, e: ErrorGuaranteed)
fn set_tainted_by_errors(&self, e: ErrorGuaranteed)
fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span)
fn infcx(&self) -> Option<&InferCtxt<'tcx>>
fn astconv(&self) -> &dyn AstConv<'tcx>where Self: Sized,
Auto Trait Implementations§
impl<'a, 'tcx> !RefUnwindSafe for FnCtxt<'a, 'tcx>
impl<'a, 'tcx> !Send for FnCtxt<'a, 'tcx>
impl<'a, 'tcx> !Sync for FnCtxt<'a, 'tcx>
impl<'a, 'tcx> Unpin for FnCtxt<'a, 'tcx>
impl<'a, 'tcx> !UnwindSafe for FnCtxt<'a, 'tcx>
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Layout§
Note: Most layout information is completely unstable and may even differ between compilations. The only exception is types with certain repr(...)
attributes. Please see the Rust Reference's “Type Layout” chapter for details on type layout guarantees.
Size: 248 bytes