pub(crate) struct ProbeContext<'a, 'tcx> {Show 17 fields
fcx: &'a FnCtxt<'a, 'tcx>,
span: Span,
mode: Mode,
method_name: Option<Ident>,
return_type: Option<Ty<'tcx>>,
orig_steps_var_values: &'a OriginalQueryValues<'tcx>,
steps: &'tcx [CandidateStep<'tcx>],
inherent_candidates: Vec<Candidate<'tcx>>,
extension_candidates: Vec<Candidate<'tcx>>,
impl_dups: FxHashSet<DefId>,
allow_similar_names: bool,
private_candidates: Vec<Candidate<'tcx>>,
private_candidate: Cell<Option<(DefKind, DefId)>>,
static_candidates: RefCell<Vec<CandidateSource>>,
unsatisfied_predicates: RefCell<Vec<(Predicate<'tcx>, Option<Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>>,
scope_expr_id: HirId,
is_suggestion: IsSuggestion,
}
Fields§
§fcx: &'a FnCtxt<'a, 'tcx>
§span: Span
§mode: Mode
§method_name: Option<Ident>
§return_type: Option<Ty<'tcx>>
§orig_steps_var_values: &'a OriginalQueryValues<'tcx>
This is the OriginalQueryValues for the steps queries that are answered in steps.
steps: &'tcx [CandidateStep<'tcx>]
§inherent_candidates: Vec<Candidate<'tcx>>
§extension_candidates: Vec<Candidate<'tcx>>
§impl_dups: FxHashSet<DefId>
§allow_similar_names: bool
When probing for names, include names that are close to the requested name (by edit distance)
private_candidates: Vec<Candidate<'tcx>>
List of potential private candidates. Will be trimmed to ones that
actually apply and then the result inserted into private_candidate
private_candidate: Cell<Option<(DefKind, DefId)>>
Some(candidate) if there is a private candidate
static_candidates: RefCell<Vec<CandidateSource>>
Collects near misses when the candidate functions are missing a self
keyword and is only
used for error reporting
unsatisfied_predicates: RefCell<Vec<(Predicate<'tcx>, Option<Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>>
Collects near misses when trait bounds for type parameters are unsatisfied and is only used for error reporting
scope_expr_id: HirId
§is_suggestion: IsSuggestion
Is this probe being done for a diagnostic? This will skip some error reporting machinery, since we don’t particularly care about, for example, similarly named candidates if we’re reporting similarly named candidates.
Implementations§
source§impl<'a, 'tcx> ProbeContext<'a, 'tcx>
impl<'a, 'tcx> ProbeContext<'a, 'tcx>
fn new( fcx: &'a FnCtxt<'a, 'tcx>, span: Span, mode: Mode, method_name: Option<Ident>, return_type: Option<Ty<'tcx>>, orig_steps_var_values: &'a OriginalQueryValues<'tcx>, steps: &'tcx [CandidateStep<'tcx>], scope_expr_id: HirId, is_suggestion: IsSuggestion, ) -> ProbeContext<'a, 'tcx>
fn reset(&mut self)
sourcefn variance(&self) -> Variance
fn variance(&self) -> Variance
When we’re looking up a method by path (UFCS), we relate the receiver
types invariantly. When we are looking up a method by the .
operator,
we relate them covariantly.
fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool)
fn assemble_inherent_candidates(&mut self)
fn assemble_probe( &mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, )
fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>)
fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId)
fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId)
fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>)
fn assemble_inherent_candidates_from_param(&mut self, param_ty: ParamTy)
fn assemble_candidates_for_bounds<F>( &mut self, bounds: impl Iterator<Item = PolyTraitRef<'tcx>>, mk_cand: F, )
fn assemble_extension_candidates_for_traits_in_scope(&mut self)
fn assemble_extension_candidates_for_all_traits(&mut self)
fn matches_return_type(&self, method: AssocItem, expected: Ty<'tcx>) -> bool
fn assemble_extension_candidates_for_trait( &mut self, import_ids: &SmallVec<[LocalDefId; 1]>, trait_def_id: DefId, )
fn candidate_method_names( &self, candidate_filter: impl Fn(&AssocItem) -> bool, ) -> Vec<Ident>
fn pick(self) -> Result<Pick<'tcx>, MethodError<'tcx>>
fn pick_core(&self) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
fn pick_all_method( &self, unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
sourcefn pick_by_value_method(
&self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
fn pick_by_value_method( &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
For each type T
in the step list, this attempts to find a method where
the (transformed) self type is exactly T
. We do however do one
transformation on the adjustment: if we are passing a region pointer in,
we will potentially reborrow it to a shorter lifetime. This allows us
to transparently pass &mut
pointers, in particular, without consuming
them for their entire lifetime.
fn pick_autorefd_method( &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, mutbl: Mutability, unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
sourcefn pick_reborrow_pin_method(
&self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
fn pick_reborrow_pin_method( &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
Looks for applicable methods if we reborrow a Pin<&mut T>
as a Pin<&T>
.
sourcefn pick_const_ptr_method(
&self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
fn pick_const_ptr_method( &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
If self_ty
is *mut T
then this picks *const T
methods. The reason why we have a
special case for this is because going from *mut T
to *const T
with autoderefs and
autorefs would require dereferencing the pointer, which is not safe.
fn pick_method( &self, self_ty: Ty<'tcx>, unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
fn consider_candidates( &self, self_ty: Ty<'tcx>, candidates: &[Candidate<'tcx>], possibly_unsatisfied_predicates: &mut Vec<(Predicate<'tcx>, Option<Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>, unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option<Result<Pick<'tcx>, MethodError<'tcx>>>
source§impl<'a, 'tcx> ProbeContext<'a, 'tcx>
impl<'a, 'tcx> ProbeContext<'a, 'tcx>
fn select_trait_candidate( &self, trait_ref: TraitRef<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>>
sourcefn candidate_source(
&self,
candidate: &Candidate<'tcx>,
self_ty: Ty<'tcx>,
) -> CandidateSource
fn candidate_source( &self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>, ) -> CandidateSource
Used for ambiguous method call error reporting. Uses probing that throws away the result internally, so do not use to make a decision that may lead to a successful compilation.
fn consider_probe( &self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>, possibly_unsatisfied_predicates: &mut Vec<(Predicate<'tcx>, Option<Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>, ) -> ProbeResult
sourcefn collapse_candidates_to_trait_pick(
&self,
self_ty: Ty<'tcx>,
probes: &[(&Candidate<'tcx>, ProbeResult)],
) -> Option<Pick<'tcx>>
fn collapse_candidates_to_trait_pick( &self, self_ty: Ty<'tcx>, probes: &[(&Candidate<'tcx>, ProbeResult)], ) -> Option<Pick<'tcx>>
Sometimes we get in a situation where we have multiple probes that are all impls of the same trait, but we don’t know which impl to use. In this case, since in all cases the external interface of the method can be determined from the trait, it’s ok not to decide. We can basically just collapse all of the probes for various impls into one where-clause probe. This will result in a pending obligation so when more type-info is available we can make the final decision.
Example (tests/ui/method-two-trait-defer-resolution-1.rs
):
trait Foo { ... }
impl Foo for Vec<i32> { ... }
impl Foo for Vec<usize> { ... }
Now imagine the receiver is Vec<_>
. It doesn’t really matter at this time which impl we
use, so it’s ok to just commit to “using the method from the trait Foo”.
sourcepub(crate) fn probe_for_similar_candidate(
&mut self,
) -> Result<Option<AssocItem>, MethodError<'tcx>>
pub(crate) fn probe_for_similar_candidate( &mut self, ) -> Result<Option<AssocItem>, MethodError<'tcx>>
Similarly to probe_for_return_type
, this method attempts to find the best matching
candidate method where the method name may have been misspelled. Similarly to other
edit distance based suggestions, we provide at most one such suggestion.
fn has_applicable_self(&self, item: &AssocItem) -> bool
fn record_static_candidate(&self, source: CandidateSource)
fn xform_self_ty( &self, item: AssocItem, impl_ty: Ty<'tcx>, args: GenericArgsRef<'tcx>, ) -> (Ty<'tcx>, Option<Ty<'tcx>>)
fn xform_method_sig( &self, method: DefId, args: GenericArgsRef<'tcx>, ) -> FnSig<'tcx>
sourcefn is_relevant_kind_for_mode(&self, kind: AssocKind) -> bool
fn is_relevant_kind_for_mode(&self, kind: AssocKind) -> bool
Determine if the given associated item type is relevant in the current context.
sourcefn matches_by_doc_alias(&self, def_id: DefId) -> bool
fn matches_by_doc_alias(&self, def_id: DefId) -> bool
Determine if the associated item with the given DefId matches the desired name via a doc alias.
Methods from Deref<Target = FnCtxt<'a, 'tcx>>§
pub(crate) 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 explain_never_type_coerced_to_unit( &self, err: &mut Diag<'_>, arm: &Arm<'tcx>, arm_ty: Ty<'tcx>, prior_arm: Option<(Option<HirId>, Ty<'tcx>, Span)>, expr: &Expr<'tcx>, )
fn suggest_removing_semicolon_for_coerce( &self, diag: &mut Diag<'_>, 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,
if_span: Span,
cond_expr: &'tcx Expr<'tcx>,
then_expr: &'tcx Expr<'tcx>,
coercion: &mut CoerceMany<'tcx, '_, T>,
) -> boolwhere
T: AsCoercionSite,
pub(crate) fn if_fallback_coercion<T>(
&self,
if_span: Span,
cond_expr: &'tcx Expr<'tcx>,
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.
sourcefn explain_if_expr(
&self,
err: &mut Diag<'_>,
ret_reason: Option<(Span, String)>,
if_span: Span,
cond_expr: &'tcx Expr<'tcx>,
then_expr: &'tcx Expr<'tcx>,
error: &mut bool,
)
fn explain_if_expr( &self, err: &mut Diag<'_>, ret_reason: Option<(Span, String)>, if_span: Span, cond_expr: &'tcx Expr<'tcx>, then_expr: &'tcx Expr<'tcx>, error: &mut bool, )
Explain why if
expressions without else
evaluate to ()
and detect likely irrefutable
if let PAT = EXPR {}
expressions that could be turned into let PAT = EXPR;
.
pub(crate) 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>, tail_defines_return_position_impl_trait: Option<LocalDefId>, ) -> ObligationCause<'tcx>
pub(crate) fn demand_scrutinee_type( &self, scrut: &'tcx Expr<'tcx>, contains_ref_bindings: Option<Mutability>, no_arms: bool, ) -> Ty<'tcx>
pub(crate) fn return_position_impl_trait_from_match_expectation( &self, expectation: Expectation<'tcx>, ) -> Option<LocalDefId>
pub(crate) fn autoderef( &'a self, span: Span, base_ty: Ty<'tcx>, ) -> Autoderef<'a, 'tcx>
pub(crate) fn try_overloaded_deref( &self, span: Span, base_ty: Ty<'tcx>, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
sourcepub(crate) fn adjust_steps(
&self,
autoderef: &Autoderef<'a, 'tcx>,
) -> Vec<Adjustment<'tcx>>
pub(crate) fn adjust_steps( &self, autoderef: &Autoderef<'a, 'tcx>, ) -> Vec<Adjustment<'tcx>>
Returns the adjustment steps.
pub(crate) fn adjust_steps_as_infer_ok( &self, autoderef: &Autoderef<'a, 'tcx>, ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>>
pub(crate) 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 Diag<'_>,
hir_id: HirId,
callee_node: &ExprKind<'_>,
callee_span: Span,
)
fn identify_bad_closure_def_and_call( &self, err: &mut Diag<'_>, 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 Diag<'_>,
call_expr: &'tcx Expr<'tcx>,
callee_expr: &'tcx Expr<'tcx>,
) -> bool
fn maybe_suggest_bad_array_definition( &self, err: &mut Diag<'_>, 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 Diag<'_>,
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 Diag<'_>, 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, 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>
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.
pub(crate) fn check_expr_closure( &self, closure: &Closure<'tcx>, expr_span: Span, expected: Expectation<'tcx>, ) -> Ty<'tcx>
sourcefn deduce_closure_signature(
&self,
expected_ty: Ty<'tcx>,
closure_kind: ClosureKind,
) -> (Option<ExpectedSig<'tcx>>, Option<ClosureKind>)
fn deduce_closure_signature( &self, expected_ty: Ty<'tcx>, closure_kind: ClosureKind, ) -> (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>, closure_kind: ClosureKind, predicates: impl DoubleEndedIterator<Item = (Predicate<'tcx>, Span)>, ) -> (Option<ExpectedSig<'tcx>>, Option<ClosureKind>)
sourcefn deduce_sig_from_projection(
&self,
cause_span: Option<Span>,
closure_kind: ClosureKind,
projection: PolyProjectionPredicate<'tcx>,
) -> Option<ExpectedSig<'tcx>>
fn deduce_sig_from_projection( &self, cause_span: Option<Span>, closure_kind: ClosureKind, 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 coroutine.
The cause_span
should be the span that caused us to
have this expected signature, or None
if we can’t readily
know that.
sourcefn extract_sig_from_projection(
&self,
cause_span: Option<Span>,
projection: PolyProjectionPredicate<'tcx>,
) -> Option<ExpectedSig<'tcx>>
fn extract_sig_from_projection( &self, cause_span: Option<Span>, projection: PolyProjectionPredicate<'tcx>, ) -> Option<ExpectedSig<'tcx>>
Given an FnOnce::Output
or AsyncFn::Output
projection, extract the args
and return type to infer a ty::PolyFnSig
for the closure.
sourcefn extract_sig_from_projection_and_future_bound(
&self,
cause_span: Option<Span>,
projection: PolyProjectionPredicate<'tcx>,
) -> Option<ExpectedSig<'tcx>>
fn extract_sig_from_projection_and_future_bound( &self, cause_span: Option<Span>, projection: PolyProjectionPredicate<'tcx>, ) -> Option<ExpectedSig<'tcx>>
When an async closure is passed to a function that has a “two-part” Fn
and Future
trait bound, like:
use std::future::Future;
fn not_exactly_an_async_closure<F, Fut>(_f: F)
where
F: FnOnce(String, u32) -> Fut,
Fut: Future<Output = i32>,
{}
The we want to be able to extract the signature to guide inference in the async
closure. We will have two projection predicates registered in this case. First,
we identify the FnOnce<Args, Output = ?Fut>
bound, and if the output type is
an inference variable ?Fut
, we check if that is bounded by a Future<Output = Ty>
projection.
This function is actually best-effort with the return type; if we don’t find a
Future
projection, we still will return arguments that we extracted from the FnOnce
projection, and the output will be an unconstrained type variable instead.
fn sig_of_closure( &self, expr_def_id: LocalDefId, decl: &FnDecl<'tcx>, closure_kind: ClosureKind, expected_sig: Option<ExpectedSig<'tcx>>, ) -> ClosureSignatures<'tcx>
sourcefn sig_of_closure_no_expectation(
&self,
expr_def_id: LocalDefId,
decl: &FnDecl<'tcx>,
closure_kind: ClosureKind,
) -> ClosureSignatures<'tcx>
fn sig_of_closure_no_expectation( &self, expr_def_id: LocalDefId, decl: &FnDecl<'tcx>, closure_kind: ClosureKind, ) -> 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<'tcx>,
closure_kind: ClosureKind,
expected_sig: ExpectedSig<'tcx>,
) -> ClosureSignatures<'tcx>
fn sig_of_closure_with_expectation( &self, expr_def_id: LocalDefId, decl: &FnDecl<'tcx>, closure_kind: ClosureKind, 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<'tcx>, expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx>
sourcefn merge_supplied_sig_with_expectation(
&self,
expr_def_id: LocalDefId,
decl: &FnDecl<'tcx>,
closure_kind: ClosureKind,
expected_sigs: ClosureSignatures<'tcx>,
) -> InferResult<'tcx, ClosureSignatures<'tcx>>
fn merge_supplied_sig_with_expectation( &self, expr_def_id: LocalDefId, decl: &FnDecl<'tcx>, closure_kind: ClosureKind, 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<'tcx>,
closure_kind: ClosureKind,
) -> PolyFnSig<'tcx>
fn supplied_sig_of_closure( &self, expr_def_id: LocalDefId, decl: &FnDecl<'tcx>, closure_kind: ClosureKind, ) -> 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,
body_def_id: LocalDefId,
) -> Option<Ty<'tcx>>
fn deduce_future_output_from_obligations( &self, body_def_id: LocalDefId, ) -> Option<Ty<'tcx>>
Invoked when we are translating the coroutine 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<'tcx>,
guar: ErrorGuaranteed,
) -> PolyFnSig<'tcx>
fn error_sig_of_closure( &self, decl: &FnDecl<'tcx>, 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, bound_sig: PolyFnSig<'tcx>, ) -> ClosureSignatures<'tcx>
sourcepub(crate) fn coerce(
&self,
expr: &'tcx Expr<'tcx>,
expr_ty: Ty<'tcx>,
target: Ty<'tcx>,
allow_two_phase: AllowTwoPhase,
cause: Option<ObligationCause<'tcx>>,
) -> RelateResult<'tcx, Ty<'tcx>>
pub(crate) fn coerce( &self, expr: &'tcx Expr<'tcx>, 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(crate) fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool
pub(crate) 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(crate) fn deref_steps_for_suggestion(
&self,
expr_ty: Ty<'tcx>,
target: Ty<'tcx>,
) -> Option<usize>
pub(crate) fn deref_steps_for_suggestion( &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 coerce expr_ty
to target
. If
it’s not possible, return None
.
sourcepub(crate) fn deref_once_mutably_for_diagnostic(
&self,
expr_ty: Ty<'tcx>,
) -> Option<Ty<'tcx>>
pub(crate) 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.
pub(crate) fn emit_type_mismatch_suggestions( &self, err: &mut Diag<'_>, expr: &Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>>, error: Option<TypeError<'tcx>>, )
pub(crate) fn emit_coerce_suggestions( &self, err: &mut Diag<'_>, 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(crate) fn demand_suptype(
&self,
sp: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
)
pub(crate) 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(crate) fn demand_suptype_diag( &'a self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Result<(), Diag<'a>>
pub(crate) fn demand_suptype_with_origin( &'a self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Result<(), Diag<'a>>
pub(crate) fn demand_eqtype( &self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, )
pub(crate) fn demand_eqtype_diag( &'a self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Result<(), Diag<'a>>
pub(crate) fn demand_eqtype_with_origin( &'a self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Result<(), Diag<'a>>
pub(crate) 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(crate) fn demand_coerce_diag(
&'a self,
expr: &'tcx Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx Expr<'tcx>>,
allow_two_phase: AllowTwoPhase,
) -> Result<Ty<'tcx>, Diag<'a>>
pub(crate) fn demand_coerce_diag( &'a self, expr: &'tcx Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> Result<Ty<'tcx>, Diag<'a>>
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(crate) fn note_source_of_type_mismatch_constraint(
&self,
err: &mut Diag<'_>,
expr: &Expr<'_>,
source: TypeMismatchSource<'tcx>,
) -> bool
pub(crate) fn note_source_of_type_mismatch_constraint( &self, err: &mut Diag<'_>, 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(crate) fn annotate_loop_expected_due_to_inference( &self, err: &mut Diag<'_>, expr: &Expr<'_>, error: Option<TypeError<'tcx>>, )
fn annotate_expected_due_to_let_ty( &self, err: &mut Diag<'_>, expr: &Expr<'_>, error: Option<TypeError<'tcx>>, )
fn annotate_alternative_method_deref( &self, err: &mut Diag<'_>, expr: &Expr<'_>, error: Option<TypeError<'tcx>>, )
pub(crate) fn get_conversion_methods_for_diagnostic( &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
.
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
pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &Expr<'_>) -> bool
fn explain_self_literal( &self, err: &mut Diag<'_>, expr: &Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, )
fn note_wrong_return_ty_due_to_generic_arg( &self, err: &mut Diag<'_>, expr: &Expr<'_>, checked_ty: Ty<'tcx>, )
pub(crate) fn check_expr_has_type_or_error( &self, expr: &'tcx Expr<'tcx>, expected_ty: Ty<'tcx>, extend_err: impl FnOnce(&mut Diag<'_>), ) -> 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>],
call: Option<&'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>], call: Option<&'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
.
sourcepub(crate) fn expr_guaranteed_to_constitute_read_for_never(
&self,
expr: &'tcx Expr<'tcx>,
) -> bool
pub(crate) fn expr_guaranteed_to_constitute_read_for_never( &self, expr: &'tcx Expr<'tcx>, ) -> bool
Whether this expression constitutes a read of value of the type that it evaluates to.
This is used to determine if we should consider the block to diverge
if the expression evaluates to !
, and if we should insert a NeverToAny
coercion for values of type !
.
This function generally returns false
if the expression is a place
expression and the parent expression is the scrutinee of a match or
the pointee of an &
addr-of expression, since both of those parent
expressions take a place and not a value.
sourcepub(crate) fn pat_guaranteed_to_constitute_read_for_never(
&self,
pat: &Pat<'_>,
) -> bool
pub(crate) fn pat_guaranteed_to_constitute_read_for_never( &self, pat: &Pat<'_>, ) -> bool
Whether this pattern constitutes a read of value of the scrutinee that
it is matching against. This is used to determine whether we should
perform NeverToAny
coercions.
See above for the nuances of what happens when this returns true.
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>, ) -> Ty<'tcx>
pub(crate) fn check_expr_path( &self, qpath: &'tcx QPath<'tcx>, expr: &'tcx Expr<'tcx>, args: Option<&'tcx [Expr<'tcx>]>, call: Option<&'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>>, hir_id: HirId, span: Span, return_expr_ty: Ty<'tcx>, return_span: Span, )
pub(crate) fn check_lhs_assignable( &self, lhs: &'tcx Expr<'tcx>, code: ErrCode, op_span: Span, adjust_err: impl FnOnce(&mut Diag<'_>), )
sourcepub(crate) fn check_for_missing_semi(
&self,
expr: &'tcx Expr<'tcx>,
err: &mut Diag<'_>,
) -> bool
pub(crate) fn check_for_missing_semi( &self, expr: &'tcx Expr<'tcx>, err: &mut Diag<'_>, ) -> bool
Check if the expression that could not be assigned to was a typoed expression that
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 LetExpr<'tcx>, hir_id: HirId, ) -> 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: &'tcx PathSegment<'tcx>,
rcvr: &'tcx Expr<'tcx>,
args: &'tcx [Expr<'tcx>],
expected: Expectation<'tcx>,
) -> Ty<'tcx>
fn check_method_call( &self, expr: &'tcx Expr<'tcx>, segment: &'tcx PathSegment<'tcx>, 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>, ) -> Ty<'tcx>
fn check_expr_repeat( &self, element: &'tcx Expr<'tcx>, count: &'tcx ArrayLen<'tcx>, expected: Expectation<'tcx>, expr: &'tcx Expr<'tcx>, ) -> Ty<'tcx>
sourcefn enforce_repeat_element_needs_copy_bound(
&self,
element: &Expr<'_>,
element_ty: Ty<'tcx>,
)
fn enforce_repeat_element_needs_copy_bound( &self, element: &Expr<'_>, element_ty: Ty<'tcx>, )
Requires that element_ty
is Copy
(unless it’s a const expression itself).
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<'tcx>, 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, hir_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: UnordMap<Ident, (FieldIdx, &FieldDef)>,
variant: &'tcx VariantDef,
hir_fields: &'tcx [ExprField<'tcx>],
args: GenericArgsRef<'tcx>,
)
fn report_missing_fields( &self, adt_ty: Ty<'tcx>, span: Span, remaining_fields: UnordMap<Ident, (FieldIdx, &FieldDef)>, variant: &'tcx VariantDef, hir_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 1 previous error
sourcefn suggest_fru_from_range_and_emit(
&self,
last_expr_field: &ExprField<'tcx>,
variant: &VariantDef,
args: GenericArgsRef<'tcx>,
err: Diag<'_>,
)
fn suggest_fru_from_range_and_emit( &self, last_expr_field: &ExprField<'tcx>, variant: &VariantDef, args: GenericArgsRef<'tcx>, err: Diag<'_>, )
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,
expr_span: Span,
private_fields: Vec<&FieldDef>,
used_fields: &'tcx [ExprField<'tcx>],
)
fn report_private_fields( &self, adt_ty: Ty<'tcx>, span: Span, expr_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 1 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
sourcefn find_adt_field(
&self,
base_def: AdtDef<'tcx>,
ident: Ident,
) -> Option<(FieldIdx, &'tcx FieldDef)>
fn find_adt_field( &self, base_def: AdtDef<'tcx>, ident: Ident, ) -> Option<(FieldIdx, &'tcx FieldDef)>
Find the position of a field named ident
in base_def
, accounting for unnammed fields.
Return whether such a field has been found. The path to it is stored in nested_fields
.
ident
must have been adjusted beforehand.
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 Diag<'_>, 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 Diag<'_>, param: ParamTy)
fn maybe_suggest_array_indexing( &self, err: &mut Diag<'_>, base: &Expr<'_>, field: Ident, len: Const<'tcx>, )
fn suggest_first_deref_field( &self, err: &mut Diag<'_>, base: &Expr<'_>, field: Ident, )
fn no_such_field_err( &self, field: Ident, expr_t: Ty<'tcx>, id: HirId, ) -> Diag<'_>
fn private_field_err(&self, field: Ident, base_did: DefId) -> Diag<'_>
pub(crate) fn get_field_candidates_considering_privacy_for_diag( &self, span: Span, base_ty: Ty<'tcx>, mod_id: DefId, hir_id: HirId, ) -> Vec<(Vec<&'tcx FieldDef>, GenericArgsRef<'tcx>)>
sourcepub(crate) fn check_for_nested_field_satisfying_condition_for_diag(
&self,
span: Span,
matches: &impl Fn(&FieldDef, Ty<'tcx>) -> bool,
candidate_field: &FieldDef,
subst: GenericArgsRef<'tcx>,
field_path: Vec<Ident>,
mod_id: DefId,
hir_id: HirId,
) -> Option<Vec<Ident>>
pub(crate) fn check_for_nested_field_satisfying_condition_for_diag( &self, span: Span, matches: &impl Fn(&FieldDef, Ty<'tcx>) -> bool, candidate_field: &FieldDef, subst: GenericArgsRef<'tcx>, field_path: Vec<Ident>, mod_id: DefId, hir_id: HirId, ) -> 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(&self, errors: &mut Vec<FulfillmentError<'tcx>>, span: Span)
fn check_expr_yield( &self, value: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx>, ) -> 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>
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>>, ) -> bool
sourcefn calculate_diverging_fallback(
&self,
unresolved_variables: &[Ty<'tcx>],
behavior: DivergingFallbackBehavior,
) -> UnordMap<Ty<'tcx>, Ty<'tcx>>
fn calculate_diverging_fallback( &self, unresolved_variables: &[Ty<'tcx>], behavior: DivergingFallbackBehavior, ) -> 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
.
fn lint_never_type_fallback_flowing_into_unsafe_code( &self, unsafe_infer_vars: &OnceCell<UnordMap<TyVid, (HirId, Span, UnsafeUseReason)>>, coercion_graph: &VecGraph<TyVid, true>, root_vid: TyVid, )
fn lint_obligations_broken_by_never_type_fallback_change( &self, behavior: DivergingFallbackBehavior, diverging_vids: &[TyVid], )
sourcefn create_coercion_graph(&self) -> VecGraph<TyVid, true>
fn create_coercion_graph(&self) -> VecGraph<TyVid, true>
Returns a graph whose nodes are (unresolved) inference variables and where
an edge ?A -> ?B
indicates that the variable ?A
is coerced to ?B
.
sourcefn root_vid(&self, ty: Ty<'tcx>) -> Option<TyVid>
fn root_vid(&self, ty: Ty<'tcx>) -> Option<TyVid>
If ty
is an unresolved type variable, returns its root vid.
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>>
fn tag(&self) -> String
pub(crate) fn local_ty(&self, span: Span, nid: HirId) -> Ty<'tcx>
pub(crate) fn write_ty(&self, id: HirId, ty: Ty<'tcx>)
pub(crate) 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(crate) fn write_method_call_and_enforce_effects( &self, hir_id: HirId, span: Span, method: MethodCallee<'tcx>, )
fn write_args(&self, node_id: HirId, args: GenericArgsRef<'tcx>)
sourcepub(crate) fn write_user_type_annotation_from_args(
&self,
hir_id: HirId,
def_id: DefId,
args: GenericArgsRef<'tcx>,
user_self_ty: Option<UserSelfTy<'tcx>>,
)
pub(crate) 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 parameters (i.e., parameters 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(crate) fn write_user_type_annotation( &self, hir_id: HirId, canonical_user_type_annotation: CanonicalUserType<'tcx>, )
pub(crate) 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(crate) fn require_type_meets( &self, ty: Ty<'tcx>, span: Span, code: ObligationCauseCode<'tcx>, def_id: DefId, )
pub(crate) fn require_type_is_sized( &self, ty: Ty<'tcx>, span: Span, code: ObligationCauseCode<'tcx>, )
pub(crate) fn require_type_is_sized_deferred( &self, ty: Ty<'tcx>, span: Span, code: ObligationCauseCode<'tcx>, )
pub(crate) fn require_type_has_static_alignment( &self, ty: Ty<'tcx>, span: Span, code: ObligationCauseCode<'tcx>, )
pub(crate) fn register_bound( &self, ty: Ty<'tcx>, def_id: DefId, cause: ObligationCause<'tcx>, )
pub(crate) fn lower_ty(&self, hir_ty: &Ty<'tcx>) -> LoweredTy<'tcx>
pub(crate) fn lower_ty_saving_user_provided_ty( &self, hir_ty: &Ty<'tcx>, ) -> Ty<'tcx>
pub(crate) fn lower_array_length(&self, length: &ArrayLen<'tcx>) -> Const<'tcx>
pub(crate) fn lower_const_arg( &self, const_arg: &'tcx ConstArg<'tcx>, param_def_id: DefId, ) -> Const<'tcx>
pub(crate) fn node_ty(&self, id: HirId) -> Ty<'tcx>
pub(crate) fn node_ty_opt(&self, id: HirId) -> Option<Ty<'tcx>>
sourcepub(crate) fn register_wf_obligation(
&self,
arg: GenericArg<'tcx>,
span: Span,
code: ObligationCauseCode<'tcx>,
)
pub(crate) 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(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, expr: &Expr<'_>)
pub(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, expr: &Expr<'_>)
Registers obligations that all args
are well-formed.
pub(crate) 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_coroutine_interiors(&self)
pub(crate) fn resolve_coroutine_interiors(&self)
Unify the inference variables corresponding to coroutine 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 coroutine
interior types, for later processing by check_coroutine_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>,
) -> Ty<'tcx>
pub(crate) fn make_overloaded_place_return_type( &self, method: MethodCallee<'tcx>, ) -> Ty<'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
.
pub(crate) fn type_var_is_sized(&self, self_ty: TyVid) -> bool
pub(crate) fn err_args( &self, len: usize, guar: ErrorGuaranteed, ) -> Vec<Ty<'tcx>>
pub(crate) fn resolve_lang_item_path( &self, lang_item: LangItem, span: Span, hir_id: HirId, ) -> (Res, Ty<'tcx>)
sourcepub(crate) fn resolve_ty_and_res_fully_qualified_call(
&self,
qpath: &'tcx QPath<'tcx>,
hir_id: HirId,
span: Span,
) -> (Res, Option<LoweredTy<'tcx>>, &'tcx [PathSegment<'tcx>])
pub(crate) fn resolve_ty_and_res_fully_qualified_call( &self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, span: Span, ) -> (Res, Option<LoweredTy<'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_fn_decl(
&self,
blk_id: HirId,
) -> Option<(LocalDefId, &'tcx FnDecl<'tcx>)>
pub(crate) fn get_fn_decl( &self, blk_id: HirId, ) -> Option<(LocalDefId, &'tcx FnDecl<'tcx>)>
Given a HirId
, return the HirId
of the enclosing function and its FnDecl
.
pub(crate) fn note_internal_mutation_in_method( &self, err: &mut Diag<'_>, expr: &Expr<'_>, expected: Option<Ty<'tcx>>, found: Ty<'tcx>, )
pub(crate) fn instantiate_value_path( &self, segments: &'tcx [PathSegment<'tcx>], self_ty: Option<LoweredTy<'tcx>>, res: Res, span: Span, path_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, instantiated 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(crate) fn try_structurally_resolve_type(
&self,
sp: Span,
ty: Ty<'tcx>,
) -> Ty<'tcx>
pub(crate) 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.
pub(crate) fn try_structurally_resolve_const( &self, sp: Span, ct: Const<'tcx>, ) -> Const<'tcx>
sourcepub(crate) fn structurally_resolve_type(
&self,
sp: Span,
ty: Ty<'tcx>,
) -> Ty<'tcx>
pub(crate) 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.
pub(crate) 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(crate) fn blame_specific_expr_if_possible(
&self,
error: &mut FulfillmentError<'tcx>,
expr: &'tcx Expr<'tcx>,
)
pub(crate) 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: &ImplDerivedCause<'tcx>,
expr: &'tcx Expr<'tcx>,
) -> Result<&'tcx Expr<'tcx>, &'tcx Expr<'tcx>>
fn blame_specific_expr_if_possible_for_derived_predicate_obligation( &self, obligation: &ImplDerivedCause<'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.
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>, ErrorGuaranteed>, 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>],
formal_output: Ty<'tcx>,
expectation: Expectation<'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>], formal_output: Ty<'tcx>, expectation: Expectation<'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: ErrCode, fn_def_id: Option<DefId>, call_span: Span, call_expr: &'tcx Expr<'tcx>, tuple_arguments: TupleArgumentsFlag, ) -> ErrorGuaranteed
fn suggest_ptr_null_mut( &self, expected_ty: Ty<'tcx>, provided_ty: Ty<'tcx>, arg: &Expr<'tcx>, err: &mut Diag<'_>, )
pub(crate) fn check_lit( &self, lit: &Lit, expected: Expectation<'tcx>, ) -> Ty<'tcx>
pub(crate) fn check_struct_path( &self, qpath: &QPath<'tcx>, hir_id: HirId, ) -> Result<(&'tcx VariantDef, Ty<'tcx>), ErrorGuaranteed>
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>)
sourcefn check_decl_local(&self, local: &'tcx LetStmt<'tcx>)
fn check_decl_local(&self, local: &'tcx LetStmt<'tcx>)
Type check a let
statement.
fn check_stmt(&self, stmt: &'tcx Stmt<'tcx>)
pub(crate) 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_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<'tcx>, path_span: Span, hir_id: HirId, ) -> (Res, LoweredTy<'tcx>)
pub(super) fn collect_unused_stmts_for_coerce_return_ty( &self, errors_causecode: Vec<(Span, ObligationCauseCode<'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 Diag<'_>, callable_def_id: Option<DefId>, callee_ty: Option<Ty<'tcx>>, call_expr: &'tcx Expr<'tcx>, expected_ty: Option<Ty<'tcx>>, expected_idx: Option<usize>, matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>, formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, is_method: bool, tuple_arguments: TupleArgumentsFlag, )
fn label_generic_mismatches( &self, err: &mut Diag<'_>, callable_def_id: Option<DefId>, matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>, provided_arg_tys: &IndexVec<ProvidedIdx, (Ty<'tcx>, Span)>, formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, is_method: bool, )
sourcefn get_hir_params_with_generics(
&self,
def_id: DefId,
is_method: bool,
) -> Option<Vec<(Option<&GenericParam<'_>>, &Param<'_>)>>
fn get_hir_params_with_generics( &self, def_id: DefId, is_method: bool, ) -> Option<Vec<(Option<&GenericParam<'_>>, &Param<'_>)>>
Returns the parameters of a function, with their generic parameters if those are the full
type of that parameter. Returns None
if the function body is unavailable (eg is an instrinsic).
sourcepub(crate) fn obligations_for_self_ty(
&self,
self_ty: TyVid,
) -> Vec<PredicateObligation<'tcx>>
pub(crate) fn obligations_for_self_ty( &self, self_ty: TyVid, ) -> Vec<PredicateObligation<'tcx>>
Returns a list of all obligations whose self type has been unified
with the unconstrained type self_ty
.
fn predicate_has_self_ty( &self, predicate: Predicate<'tcx>, expected_vid: TyVid, ) -> bool
fn type_matches_expected_vid(&self, expected_vid: TyVid, ty: Ty<'tcx>) -> bool
pub(crate) fn obligations_for_self_ty_next( &self, self_ty: TyVid, ) -> Vec<PredicateObligation<'tcx>>
pub(crate) fn body_fn_sig(&self) -> Option<FnSig<'tcx>>
pub(crate) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diag<'_>)
sourcepub(crate) fn suggest_mismatched_types_on_tail(
&self,
err: &mut Diag<'_>,
expr: &'tcx Expr<'tcx>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
blk_id: HirId,
) -> bool
pub(crate) fn suggest_mismatched_types_on_tail( &self, err: &mut Diag<'_>, 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 Diag<'_>,
expr: &Expr<'_>,
found: Ty<'tcx>,
can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
) -> bool
pub(crate) fn suggest_fn_call( &self, err: &mut Diag<'_>, 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(crate) fn suggest_two_fn_call( &self, err: &mut Diag<'_>, 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(crate) fn suggest_remove_last_method_call( &self, err: &mut Diag<'_>, expr: &Expr<'tcx>, expected: Ty<'tcx>, ) -> bool
pub(crate) fn suggest_deref_ref_or_into( &self, err: &mut Diag<'_>, expr: &Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>>, ) -> bool
sourcefn deconstruct_option_or_result(
&self,
found_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
) -> Option<(Ty<'tcx>, Ty<'tcx>, Option<(Ty<'tcx>, Ty<'tcx>)>)>
fn deconstruct_option_or_result( &self, found_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, ) -> Option<(Ty<'tcx>, Ty<'tcx>, Option<(Ty<'tcx>, Ty<'tcx>)>)>
If ty
is Option<T>
, returns T, T, None
.
If ty
is Result<T, E>
, returns T, T, Some(E, E)
.
Otherwise, returns None
.
sourcepub(crate) fn suggest_boxing_when_appropriate(
&self,
err: &mut Diag<'_>,
span: Span,
hir_id: HirId,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) -> bool
pub(crate) fn suggest_boxing_when_appropriate( &self, err: &mut Diag<'_>, 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 Diag<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) -> bool
pub(crate) fn suggest_no_capture_closure( &self, err: &mut Diag<'_>, 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 Diag<'_>,
expr: &Expr<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) -> bool
pub(crate) fn suggest_calling_boxed_future_when_appropriate( &self, err: &mut Diag<'_>, expr: &Expr<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool
When encountering an impl Future
where BoxFuture
is expected, suggest Box::pin
.
sourcepub(crate) fn suggest_missing_semicolon(
&self,
err: &mut Diag<'_>,
expression: &'tcx Expr<'tcx>,
expected: Ty<'tcx>,
needs_block: bool,
)
pub(crate) fn suggest_missing_semicolon( &self, err: &mut Diag<'_>, 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 Diag<'_>,
fn_decl: &FnDecl<'tcx>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
fn_id: LocalDefId,
) -> bool
pub(crate) fn suggest_missing_return_type( &self, err: &mut Diag<'_>, fn_decl: &FnDecl<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, fn_id: LocalDefId, ) -> 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 can_add_return_type(&self, fn_id: LocalDefId) -> bool
fn can_add_return_type(&self, fn_id: LocalDefId) -> bool
Checks whether we can add a return type to a function. Assumes given function doesn’t have a explicit return type.
fn try_note_caller_chooses_ty_for_ty_param( &self, diag: &mut Diag<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, )
sourcefn try_suggest_return_impl_trait(
&self,
err: &mut Diag<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
fn_id: LocalDefId,
)
fn try_suggest_return_impl_trait( &self, err: &mut Diag<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, fn_id: LocalDefId, )
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 Diag<'_>, expr: &'tcx Expr<'tcx>, fn_decl: &FnDecl<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, id: HirId, fn_id: LocalDefId, )
pub(crate) fn suggest_missing_parentheses( &self, err: &mut Diag<'_>, expr: &Expr<'_>, ) -> bool
sourcepub(crate) fn suggest_block_to_brackets_peeling_refs(
&self,
diag: &mut Diag<'_>,
expr: &Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
) -> bool
pub(crate) fn suggest_block_to_brackets_peeling_refs( &self, diag: &mut Diag<'_>, 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 Diag<'_>, expr: &Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, ) -> bool
pub(crate) fn suggest_copied_cloned_or_as_ref( &self, diag: &mut Diag<'_>, expr: &Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, ) -> bool
pub(crate) fn suggest_into( &self, diag: &mut Diag<'_>, expr: &Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, ) -> bool
sourcepub(crate) fn suggest_option_to_bool(
&self,
diag: &mut Diag<'_>,
expr: &Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
) -> bool
pub(crate) fn suggest_option_to_bool( &self, diag: &mut Diag<'_>, 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()
pub(crate) fn suggest_deref_unwrap_or( &self, err: &mut Diag<'_>, callee_ty: Option<Ty<'tcx>>, call_ident: Option<Ident>, expected_ty: Ty<'tcx>, provided_ty: Ty<'tcx>, provided_expr: &Expr<'tcx>, is_method: bool, )
sourcepub(crate) fn suggest_block_to_brackets(
&self,
diag: &mut Diag<'_>,
blk: &Block<'_>,
blk_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
)
pub(crate) fn suggest_block_to_brackets( &self, diag: &mut Diag<'_>, 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 Diag<'_>, expr: &Expr<'_>, expected_ty: Ty<'tcx>, ) -> bool
sourcepub(crate) fn suggest_null_ptr_for_literal_zero_given_to_ptr_arg(
&self,
err: &mut Diag<'_>,
expr: &Expr<'_>,
expected_ty: Ty<'tcx>,
) -> bool
pub(crate) fn suggest_null_ptr_for_literal_zero_given_to_ptr_arg( &self, err: &mut Diag<'_>, 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 Diag<'_>, expr: &Expr<'tcx>, 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 Diag<'_>,
expected_ty: Ty<'tcx>,
found_ty: Ty<'tcx>,
expr: &Expr<'_>,
)
pub(crate) fn note_type_is_not_clone( &self, diag: &mut Diag<'_>, 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.
pub(crate) fn is_field_suggestable( &self, field: &FieldDef, hir_id: HirId, span: Span, ) -> bool
pub(crate) fn suggest_missing_unwrap_expect( &self, err: &mut Diag<'_>, expr: &Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool
pub(crate) fn suggest_coercing_result_via_try_operator( &self, err: &mut Diag<'_>, expr: &Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool
pub(crate) fn suggest_returning_value_after_loop( &self, err: &mut Diag<'_>, expr: &Expr<'tcx>, expected: Ty<'tcx>, ) -> bool
sourcepub(crate) fn suggest_compatible_variants(
&self,
err: &mut Diag<'_>,
expr: &Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
) -> bool
pub(crate) fn suggest_compatible_variants( &self, err: &mut Diag<'_>, 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)
pub(crate) fn suggest_non_zero_new_unwrap( &self, err: &mut Diag<'_>, expr: &Expr<'_>, expected: Ty<'tcx>, expr_ty: Ty<'tcx>, ) -> bool
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 suggest_deref_or_ref(
&self,
expr: &Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
) -> Option<(Vec<(Span, String)>, String, Applicability, bool, bool)>
pub(crate) 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
!”.
sourcefn is_else_if_block(&self, expr: &Expr<'_>) -> bool
fn is_else_if_block(&self, expr: &Expr<'_>) -> bool
Returns whether the given expression is an else if
.
pub(crate) fn suggest_cast( &self, err: &mut Diag<'_>, expr: &Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, expected_ty_expr: Option<&'tcx Expr<'tcx>>, ) -> bool
sourcepub(crate) fn suggest_method_call_on_range_literal(
&self,
err: &mut Diag<'_>,
expr: &Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
)
pub(crate) fn suggest_method_call_on_range_literal( &self, err: &mut Diag<'_>, expr: &Expr<'tcx>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, )
Identify when the user has written foo..bar()
instead of foo.bar()
.
sourcepub(crate) fn suggest_return_binding_for_missing_tail_expr(
&self,
err: &mut Diag<'_>,
expr: &Expr<'_>,
checked_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
)
pub(crate) fn suggest_return_binding_for_missing_tail_expr( &self, err: &mut Diag<'_>, 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.
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'a>
pub(crate) fn cause( &self, span: Span, code: ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx>
pub(crate) fn misc(&self, span: Span) -> ObligationCause<'tcx>
pub(crate) fn sess(&self) -> &Session
sourcepub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx>
pub(crate) 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 InferCtxtErrorExt::err_ctxt
to start one without a TypeckResults
.
pub(crate) fn check_transmute( &self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId, )
pub(crate) 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: &'tcx PathSegment<'tcx>, ) -> ConfirmResult<'tcx>
pub(crate) 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<'tcx>, ) -> ConfirmResult<'tcx>
pub(super) fn lint_edition_dependent_dot_call( &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>
sourcefn adjust_expr(
&self,
pick: &Pick<'tcx>,
expr: &Expr<'tcx>,
outer: Span,
) -> (String, bool)
fn adjust_expr( &self, pick: &Pick<'tcx>, expr: &Expr<'tcx>, outer: Span, ) -> (String, bool)
Creates a string version of the expr
that includes explicit adjustments.
Returns the string and also a bool indicating whether this is a precise
suggestion.
sourcepub(crate) fn probe_for_return_type_for_diagnostic(
&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(crate) fn probe_for_return_type_for_diagnostic( &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(crate) 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, ) -> Result<Vec<Candidate<'tcx>>, MethodError<'tcx>>
pub(crate) 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>>
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool
fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool
fn impl_into_iterator_should_be_iterator( &self, ty: Ty<'tcx>, span: Span, unsatisfied_predicates: &Vec<(Predicate<'_>, Option<Predicate<'_>>, Option<ObligationCause<'_>>)>, ) -> bool
pub(crate) fn report_method_error( &self, call_id: HirId, rcvr_ty: Ty<'tcx>, error: MethodError<'tcx>, expected: Expectation<'tcx>, trait_missing_method: bool, ) -> ErrorGuaranteed
fn suggest_missing_writer( &self, rcvr_ty: Ty<'tcx>, rcvr_expr: &Expr<'tcx>, ) -> Diag<'_>
fn suggest_use_shadowed_binding_with_method( &self, self_source: SelfSource<'tcx>, method_name: Ident, ty_str_reported: &str, err: &mut Diag<'_>, )
fn report_no_match_method_error( &self, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, expr_id: HirId, source: SelfSource<'tcx>, args: Option<&'tcx [Expr<'tcx>]>, sugg_span: Span, no_match_data: &mut NoMatchData<'tcx>, expected: Expectation<'tcx>, trait_missing_method: bool, ) -> ErrorGuaranteed
sourcefn lookup_segments_chain_for_no_match_method(
&self,
err: &mut Diag<'_>,
item_name: Ident,
item_kind: &str,
source: SelfSource<'tcx>,
no_match_data: &NoMatchData<'tcx>,
)
fn lookup_segments_chain_for_no_match_method( &self, err: &mut Diag<'_>, item_name: Ident, item_kind: &str, source: SelfSource<'tcx>, no_match_data: &NoMatchData<'tcx>, )
If an appropriate error source is not found, check method chain for possible candidates
fn find_likely_intended_associated_item( &self, err: &mut Diag<'_>, similar_candidate: AssocItem, span: Span, args: Option<&'tcx [Expr<'tcx>]>, mode: Mode, )
pub(crate) fn confusable_method_name( &self, err: &mut Diag<'_>, rcvr_ty: Ty<'tcx>, item_name: Ident, call_args: Option<Vec<Ty<'tcx>>>, ) -> Option<Symbol>
fn note_candidates_on_method_error( &self, rcvr_ty: Ty<'tcx>, item_name: Ident, self_source: SelfSource<'tcx>, args: Option<&'tcx [Expr<'tcx>]>, span: Span, err: &mut Diag<'_>, sources: &mut Vec<CandidateSource>, sugg_span: Option<Span>, )
sourcefn find_builder_fn(&self, err: &mut Diag<'_>, rcvr_ty: Ty<'tcx>, expr_id: HirId)
fn find_builder_fn(&self, err: &mut Diag<'_>, rcvr_ty: Ty<'tcx>, expr_id: HirId)
Look at all the associated functions without receivers in the type’s inherent impls
to look for builders that return Self
, Option<Self>
or Result<Self, _>
.
sourcefn suggest_associated_call_syntax(
&self,
err: &mut Diag<'_>,
static_candidates: &Vec<CandidateSource>,
rcvr_ty: Ty<'tcx>,
source: SelfSource<'tcx>,
item_name: Ident,
args: Option<&'tcx [Expr<'tcx>]>,
sugg_span: Span,
)
fn suggest_associated_call_syntax( &self, err: &mut Diag<'_>, static_candidates: &Vec<CandidateSource>, rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx>, item_name: Ident, args: Option<&'tcx [Expr<'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 Diag<'_>,
) -> bool
fn suggest_calling_field_as_fn( &self, span: Span, rcvr_ty: Ty<'tcx>, expr: &Expr<'_>, item_name: Ident, err: &mut Diag<'_>, ) -> 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 report_failed_method_call_on_range_end(
&self,
tcx: TyCtxt<'tcx>,
actual: Ty<'tcx>,
source: SelfSource<'tcx>,
span: Span,
item_name: Ident,
ty_str: &str,
) -> Result<(), ErrorGuaranteed>
fn report_failed_method_call_on_range_end( &self, tcx: TyCtxt<'tcx>, actual: Ty<'tcx>, source: SelfSource<'tcx>, span: Span, item_name: Ident, ty_str: &str, ) -> Result<(), ErrorGuaranteed>
Suggest possible range with adding parentheses, for example:
when encountering 0..1.map(|i| i + 1)
suggest (0..1).map(|i| i + 1)
.
fn report_failed_method_call_on_numerical_infer_var( &self, tcx: TyCtxt<'tcx>, actual: Ty<'tcx>, source: SelfSource<'_>, span: Span, item_kind: &str, item_name: Ident, ty_str: &str, ) -> Result<(), ErrorGuaranteed>
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 Diag<'_>,
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 Diag<'_>, 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 Diag<'_>, source: SelfSource<'tcx>, actual: Ty<'tcx>, item_name: Ident, )
pub(crate) fn note_unmet_impls_on_type( &self, err: &mut Diag<'_>, errors: Vec<FulfillmentError<'tcx>>, suggest_derive: bool, )
fn note_predicate_source_and_get_derives( &self, err: &mut Diag<'_>, unsatisfied_predicates: &[(Predicate<'tcx>, Option<Predicate<'tcx>>, Option<ObligationCause<'tcx>>)], ) -> Vec<(String, Span, Symbol)>
pub(crate) fn suggest_derive( &self, err: &mut Diag<'_>, unsatisfied_predicates: &[(Predicate<'tcx>, Option<Predicate<'tcx>>, Option<ObligationCause<'tcx>>)], ) -> bool
fn note_derefed_ty_has_method( &self, err: &mut Diag<'_>, 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 Diag<'_>, item_name: Ident, ty: Ty<'tcx>, call: &Expr<'_>, span: Span, return_type: Option<Ty<'tcx>>, )
fn suggest_use_candidates<F>( &self, candidates: Vec<DefId>, handle_candidates: F, )
fn suggest_valid_traits( &self, err: &mut Diag<'_>, item_name: Ident, valid_out_of_scope_traits: Vec<DefId>, explain: bool, ) -> bool
fn suggest_traits_to_import( &self, err: &mut Diag<'_>, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, inputs_len: Option<usize>, source: SelfSource<'tcx>, valid_out_of_scope_traits: Vec<DefId>, static_candidates: &[CandidateSource], unsatisfied_bounds: bool, return_type: Option<Ty<'tcx>>, trait_missing_method: bool, )
fn detect_and_explain_multiple_crate_versions( &self, err: &mut Diag<'_>, item_def_id: DefId, hir_id: HirId, rcvr_ty: Option<Ty<'_>>, ) -> bool
sourcepub(crate) fn suggest_else_fn_with_closure(
&self,
err: &mut Diag<'_>,
expr: &Expr<'_>,
found: Ty<'tcx>,
expected: Ty<'tcx>,
) -> bool
pub(crate) fn suggest_else_fn_with_closure( &self, err: &mut Diag<'_>, 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
.
sourcepub(crate) fn method_exists_for_diagnostic(
&self,
method_name: Ident,
self_ty: Ty<'tcx>,
call_expr_id: HirId,
return_type: Option<Ty<'tcx>>,
) -> bool
pub(crate) fn method_exists_for_diagnostic( &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 Diag<'_>,
msg: impl Into<SubdiagMessage> + Debug,
method_name: Ident,
self_ty: Ty<'tcx>,
call_expr: &Expr<'tcx>,
span: Option<Span>,
)
pub(crate) fn suggest_method_call( &self, err: &mut Diag<'_>, msg: impl Into<SubdiagMessage> + 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(crate) fn lookup_method(
&self,
self_ty: Ty<'tcx>,
segment: &'tcx PathSegment<'tcx>,
span: Span,
call_expr: &'tcx Expr<'tcx>,
self_expr: &'tcx Expr<'tcx>,
args: &'tcx [Expr<'tcx>],
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>>
pub(crate) fn lookup_method( &self, self_ty: Ty<'tcx>, segment: &'tcx PathSegment<'tcx>, 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(crate) fn lookup_method_for_diagnostic( &self, self_ty: Ty<'tcx>, segment: &PathSegment<'tcx>, span: Span, call_expr: &'tcx Expr<'tcx>, self_expr: &'tcx Expr<'tcx>, ) -> Result<MethodCallee<'tcx>, MethodError<'tcx>>
pub(crate) fn lookup_probe( &self, method_name: Ident, self_ty: Ty<'tcx>, call_expr: &Expr<'_>, scope: ProbeScope, ) -> Result<Pick<'tcx>, MethodError<'tcx>>
pub(crate) 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>, GenericArgsRef<'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: GenericArgsRef<'tcx>, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
sourcepub(crate) 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(crate) 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
sourcefn associated_value(&self, def_id: DefId, item_name: Ident) -> Option<AssocItem>
fn associated_value(&self, def_id: DefId, item_name: Ident) -> Option<AssocItem>
Finds item with name item_name
defined in impl/trait def_id
and return it, or None
, if no such item was defined there.
sourcepub(crate) 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(crate) 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(crate) 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(crate) 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 Diag<'_>,
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 Diag<'_>, 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(crate) 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_expr, lhs_ty): (&'tcx Expr<'tcx>, Ty<'tcx>), opt_rhs: Option<(&'tcx Expr<'tcx>, Ty<'tcx>)>, op: Op, expected: Expectation<'tcx>, ) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>>
fn pattern_cause( &self, ti: &TopInfo<'tcx>, cause_span: Span, ) -> ObligationCause<'tcx>
fn demand_eqtype_pat_diag( &'a self, cause_span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ti: &TopInfo<'tcx>, ) -> Result<(), Diag<'a>>
fn demand_eqtype_pat( &self, cause_span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ti: &TopInfo<'tcx>, ) -> Result<(), ErrorGuaranteed>
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 binding_mode
(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_br: ByRef,
adjust_mode: AdjustMode,
max_ref_mutbl: MutblCap,
) -> (Ty<'tcx>, ByRef, MutblCap)
fn calc_default_binding_mode( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_br: ByRef, adjust_mode: AdjustMode, max_ref_mutbl: MutblCap, ) -> (Ty<'tcx>, ByRef, MutblCap)
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_br: ByRef,
max_ref_mutbl: MutblCap,
) -> (Ty<'tcx>, ByRef, MutblCap)
fn peel_off_references( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_br: ByRef, max_ref_mutbl: MutblCap, ) -> (Ty<'tcx>, ByRef, MutblCap)
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 Diag<'_>, 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>, user_bind_annot: BindingMode, var_id: HirId, ident: Ident, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx>
sourcefn check_binding_alt_eq_ty(
&self,
ba: BindingMode,
span: Span,
var_id: HirId,
ty: Ty<'tcx>,
ti: &TopInfo<'tcx>,
)
fn check_binding_alt_eq_ty( &self, ba: BindingMode, 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 Diag<'_>, span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ba: BindingMode, )
sourcefn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>)
fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>)
Precondition: pat is a Ref(_)
pattern
fn check_dereferenceable( &self, span: Span, expected: Ty<'tcx>, inner: &Pat<'_>, ) -> Result<(), ErrorGuaranteed>
fn check_pat_struct( &self, pat: &'tcx Pat<'tcx>, qpath: &QPath<'tcx>, 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<LoweredTy<'tcx>>, &'tcx [PathSegment<'tcx>]), expected: Ty<'tcx>, ti: &TopInfo<'tcx>, ) -> Ty<'tcx>
fn maybe_suggest_range_literal( &self, e: &mut Diag<'_>, opt_def_id: Option<DefId>, ident: Ident, ) -> bool
fn emit_bad_pat_path( &self, e: Diag<'_>, 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 emit_err_pat_wrong_number_of_fields( &self, pat_span: Span, res: Res, qpath: &QPath<'_>, subpats: &'tcx [Pat<'tcx>], fields: &'tcx [FieldDef], expected: Ty<'tcx>, had_err: Result<(), ErrorGuaranteed>, ) -> 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>, ) -> Result<(), ErrorGuaranteed>
fn error_tuple_variant_index_shorthand( &self, variant: &VariantDef, pat: &Pat<'_>, fields: &[PatField<'_>], ) -> Result<(), 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: GenericArgsRef<'tcx>, ) -> Diag<'a>
fn error_tuple_variant_as_struct_pat( &self, pat: &Pat<'_>, fields: &'tcx [PatField<'tcx>], variant: &VariantDef, ) -> Result<(), 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>],
) -> Diag<'a>
fn error_no_accessible_fields( &self, pat: &Pat<'_>, fields: &'tcx [PatField<'tcx>], ) -> Diag<'a>
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>],
) -> Diag<'a>
fn error_unmentioned_fields( &self, pat: &Pat<'_>, unmentioned_fields: &[(&FieldDef, Ident)], have_inaccessible_fields: bool, fields: &'tcx [PatField<'tcx>], ) -> Diag<'a>
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_deref( &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>, pat_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 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>, pat_info: PatInfo<'_, 'tcx>, ) -> ErrorGuaranteed
fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'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(crate) fn convert_place_derefs_to_mutable(&self, expr: &Expr<'_>)
pub(crate) 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<'_>, )
pub(crate) fn closure_analyze(&self, body: &'tcx Body<'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.
sourcefn coroutine_body_consumes_upvars(
&self,
coroutine_def_id: LocalDefId,
body: &'tcx Body<'tcx>,
) -> bool
fn coroutine_body_consumes_upvars( &self, coroutine_def_id: LocalDefId, body: &'tcx Body<'tcx>, ) -> bool
Determines whether the body of the coroutine uses its upvars in a way that
consumes (i.e. moves) the value, which would force the coroutine to FnOnce
.
In a more detailed comment above, we care whether this happens, since if
this happens, we want to force the coroutine to move all of the upvars it
would’ve borrowed from the parent coroutine-closure.
This only really makes sense to be called on the child coroutine of a coroutine-closure.
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 coroutines 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.
pub(crate) fn resolve_type_vars_in_body( &self, body: &'tcx Body<'tcx>, ) -> &'tcx TypeckResults<'tcx>
Methods from Deref<Target = TypeckRootCtxt<'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
fn update_infer_var_info(&self, obligation: &PredicateObligation<'tcx>)
Methods from Deref<Target = InferCtxt<'tcx>>§
pub fn at<'a>( &'a self, cause: &'a ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, ) -> At<'a, 'tcx>
sourcepub fn fork(&self) -> InferCtxt<'tcx>
pub fn fork(&self) -> InferCtxt<'tcx>
Forks the inference context, creating a new inference context with the same inference variables in the same state. This can be used to “branch off” many tests from the same common state.
sourcepub fn fork_with_intercrate(&self, intercrate: bool) -> InferCtxt<'tcx>
pub fn fork_with_intercrate(&self, intercrate: bool) -> InferCtxt<'tcx>
Forks the inference context, creating a new inference context with the same inference variables in the same state, except possibly changing the intercrate mode. This can be used to “branch off” many tests from the same common state. Used in negative coherence.
sourcepub fn canonicalize_query<V>(
&self,
value: ParamEnvAnd<'tcx, V>,
query_state: &mut OriginalQueryValues<'tcx>,
) -> Canonical<TyCtxt<'tcx>, ParamEnvAnd<'tcx, V>>where
V: TypeFoldable<TyCtxt<'tcx>>,
pub fn canonicalize_query<V>(
&self,
value: ParamEnvAnd<'tcx, V>,
query_state: &mut OriginalQueryValues<'tcx>,
) -> Canonical<TyCtxt<'tcx>, ParamEnvAnd<'tcx, V>>where
V: TypeFoldable<TyCtxt<'tcx>>,
Canonicalizes a query value V
. When we canonicalize a query,
we not only canonicalize unbound inference variables, but we
also replace all free regions whatsoever. So for example a
query like T: Trait<'static>
would be canonicalized to
T: Trait<'?0>
with a mapping M that maps '?0
to 'static
.
To get a good understanding of what is happening here, check out the chapter in the rustc dev guide.
sourcepub fn canonicalize_response<V>(&self, value: V) -> Canonical<TyCtxt<'tcx>, V>where
V: TypeFoldable<TyCtxt<'tcx>>,
pub fn canonicalize_response<V>(&self, value: V) -> Canonical<TyCtxt<'tcx>, V>where
V: TypeFoldable<TyCtxt<'tcx>>,
Canonicalizes a query response V
. When we canonicalize a
query response, we only canonicalize unbound inference
variables, and we leave other free regions alone. So,
continuing with the example from canonicalize_query
, if
there was an input query T: Trait<'static>
, it would have
been canonicalized to
T: Trait<'?0>
with a mapping M that maps '?0
to 'static
. But if we found that there
exists only one possible impl of Trait
, and it looks like
impl<T> Trait<'static> for T { .. }
then we would prepare a query result R that (among other
things) includes a mapping to '?0 := 'static
. When
canonicalizing this query result R, we would leave this
reference to 'static
alone.
To get a good understanding of what is happening here, check out the chapter in the rustc dev guide.
pub fn canonicalize_user_type_annotation<V>(
&self,
value: V,
) -> Canonical<TyCtxt<'tcx>, V>where
V: TypeFoldable<TyCtxt<'tcx>>,
sourcepub fn make_canonicalized_query_response<T>(
&self,
inference_vars: CanonicalVarValues<TyCtxt<'tcx>>,
answer: T,
fulfill_cx: &mut (dyn TraitEngine<'tcx, ScrubbedTraitError<'tcx>> + 'tcx),
) -> Result<&'tcx Canonical<TyCtxt<'tcx>, QueryResponse<'tcx, T>>, NoSolution>where
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
Canonical<TyCtxt<'tcx>, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
pub fn make_canonicalized_query_response<T>(
&self,
inference_vars: CanonicalVarValues<TyCtxt<'tcx>>,
answer: T,
fulfill_cx: &mut (dyn TraitEngine<'tcx, ScrubbedTraitError<'tcx>> + 'tcx),
) -> Result<&'tcx Canonical<TyCtxt<'tcx>, QueryResponse<'tcx, T>>, NoSolution>where
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
Canonical<TyCtxt<'tcx>, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
This method is meant to be invoked as the final step of a canonical query implementation. It is given:
- the instantiated variables
inference_vars
created from the query key - the result
answer
of the query - a fulfillment context
fulfill_cx
that may contain various obligations which have yet to be proven.
Given this, the function will process the obligations pending
in fulfill_cx
:
- If all the obligations can be proven successfully, it will
package up any resulting region obligations (extracted from
infcx
) along with the fully resolved valueanswer
into a query result (which is then itself canonicalized). - If some obligations can be neither proven nor disproven, then the same thing happens, but the resulting query is marked as ambiguous.
- Finally, if any of the obligations result in a hard error,
then
Err(NoSolution)
is returned.
sourcepub fn make_query_response_ignoring_pending_obligations<T>(
&self,
inference_vars: CanonicalVarValues<TyCtxt<'tcx>>,
answer: T,
) -> Canonical<TyCtxt<'tcx>, QueryResponse<'tcx, T>>
pub fn make_query_response_ignoring_pending_obligations<T>( &self, inference_vars: CanonicalVarValues<TyCtxt<'tcx>>, answer: T, ) -> Canonical<TyCtxt<'tcx>, QueryResponse<'tcx, T>>
A version of make_canonicalized_query_response
that does
not pack in obligations, for contexts that want to drop
pending obligations instead of treating them as an ambiguity (e.g.
typeck “probing” contexts).
If you DO want to keep track of pending obligations (which include all region obligations, so this includes all cases that care about regions) with this function, you have to do it yourself, by e.g., having them be a part of the answer.
sourcepub fn clone_opaque_types_for_query_response(
&self,
) -> Vec<(OpaqueTypeKey<TyCtxt<'tcx>>, Ty<'tcx>)>
pub fn clone_opaque_types_for_query_response( &self, ) -> Vec<(OpaqueTypeKey<TyCtxt<'tcx>>, Ty<'tcx>)>
Used by the new solver as that one takes the opaque types at the end of a probe to deal with multiple candidates without having to recompute them.
sourcepub fn instantiate_query_response_and_region_obligations<R>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ParamEnv<'tcx>,
original_values: &OriginalQueryValues<'tcx>,
query_response: &Canonical<TyCtxt<'tcx>, QueryResponse<'tcx, R>>,
) -> Result<InferOk<'tcx, R>, TypeError<TyCtxt<'tcx>>>
pub fn instantiate_query_response_and_region_obligations<R>( &self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, original_values: &OriginalQueryValues<'tcx>, query_response: &Canonical<TyCtxt<'tcx>, QueryResponse<'tcx, R>>, ) -> Result<InferOk<'tcx, R>, TypeError<TyCtxt<'tcx>>>
Given the (canonicalized) result to a canonical query, instantiates the result so it can be used, plugging in the values from the canonical query. (Note that the result may have been ambiguous; you should check the certainty level of the query before applying this function.)
To get a good understanding of what is happening here, check out the chapter in the rustc dev guide.
sourcepub fn instantiate_nll_query_response_and_region_obligations<R>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ParamEnv<'tcx>,
original_values: &OriginalQueryValues<'tcx>,
query_response: &Canonical<TyCtxt<'tcx>, QueryResponse<'tcx, R>>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
) -> Result<InferOk<'tcx, R>, TypeError<TyCtxt<'tcx>>>
pub fn instantiate_nll_query_response_and_region_obligations<R>( &self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, original_values: &OriginalQueryValues<'tcx>, query_response: &Canonical<TyCtxt<'tcx>, QueryResponse<'tcx, R>>, output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, ) -> Result<InferOk<'tcx, R>, TypeError<TyCtxt<'tcx>>>
An alternative to
instantiate_query_response_and_region_obligations
that is more
efficient for NLL. NLL is a bit more advanced in the
“transition to chalk” than the rest of the compiler. During
the NLL type check, all of the “processing” of types and
things happens in queries – the NLL checker itself is only
interested in the region obligations ('a: 'b
or T: 'b
)
that come out of these queries, which it wants to convert into
MIR-based constraints and solve. Therefore, it is most
convenient for the NLL Type Checker to directly consume
the QueryOutlivesConstraint
values that arise from doing a
query. This is contrast to other parts of the compiler, which
would prefer for those QueryOutlivesConstraint
to be converted
into the older infcx-style constraints (e.g., calls to
sub_regions
or register_region_obligation
).
Therefore, instantiate_nll_query_response_and_region_obligations
performs the same
basic operations as instantiate_query_response_and_region_obligations
but
it returns its result differently:
- It creates an instantiation
S
that maps from the original query variables to the values computed in the query result. If any errors arise, they are propagated back as anErr
result. - In the case of a successful instantiation, we will append
QueryOutlivesConstraint
values onto theoutput_query_region_constraints
vector for the solver to use (if an error arises, some values may also be pushed, but they should be ignored). - It can happen (though it rarely does currently) that equating types and things will give rise to subobligations that must be processed. In this case, those subobligations are propagated back in the return value.
- Finally, the query result (of type
R
) is propagated back, after applying the instantiationS
.
pub fn query_outlives_constraint_to_obligation( &self, _: (OutlivesPredicate<TyCtxt<'tcx>, GenericArg<'tcx>>, ConstraintCategory<'tcx>), cause: ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, ) -> Obligation<'tcx, Predicate<'tcx>>
sourcepub fn instantiate_canonical<T>(
&self,
span: Span,
canonical: &Canonical<TyCtxt<'tcx>, T>,
) -> (T, CanonicalVarValues<TyCtxt<'tcx>>)where
T: TypeFoldable<TyCtxt<'tcx>>,
pub fn instantiate_canonical<T>(
&self,
span: Span,
canonical: &Canonical<TyCtxt<'tcx>, T>,
) -> (T, CanonicalVarValues<TyCtxt<'tcx>>)where
T: TypeFoldable<TyCtxt<'tcx>>,
Creates an instantiation S for the canonical value with fresh inference variables and placeholders then applies it to the canonical value. Returns both the instantiated result and the instantiation S.
This can be invoked as part of constructing an
inference context at the start of a query (see
InferCtxtBuilder::build_with_canonical
). It basically
brings the canonical value “into scope” within your new infcx.
At the end of processing, the instantiation S (once canonicalized) then represents the values that you computed for each of the canonical inputs to your query.
sourcepub fn instantiate_canonical_var(
&self,
span: Span,
cv_info: CanonicalVarInfo<TyCtxt<'tcx>>,
universe_map: impl Fn(UniverseIndex) -> UniverseIndex,
) -> GenericArg<'tcx>
pub fn instantiate_canonical_var( &self, span: Span, cv_info: CanonicalVarInfo<TyCtxt<'tcx>>, universe_map: impl Fn(UniverseIndex) -> UniverseIndex, ) -> GenericArg<'tcx>
Given the “info” about a canonical variable, creates a fresh variable for it. If this is an existentially quantified variable, then you’ll get a new inference variable; if it is a universally quantified variable, you get a placeholder.
FIXME(-Znext-solver): This is public because it’s used by the new trait solver which has a different canonicalization routine. We should somehow deduplicate all of this.
sourcepub fn replace_opaque_types_with_inference_vars<T>(
&self,
value: T,
body_id: LocalDefId,
span: Span,
param_env: ParamEnv<'tcx>,
) -> InferOk<'tcx, T>where
T: TypeFoldable<TyCtxt<'tcx>>,
pub fn replace_opaque_types_with_inference_vars<T>(
&self,
value: T,
body_id: LocalDefId,
span: Span,
param_env: ParamEnv<'tcx>,
) -> InferOk<'tcx, T>where
T: TypeFoldable<TyCtxt<'tcx>>,
This is a backwards compatibility hack to prevent breaking changes from lazy TAIT around RPIT handling.
pub fn handle_opaque_type( &self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span, param_env: ParamEnv<'tcx>, ) -> Result<Vec<Goal<TyCtxt<'tcx>, Predicate<'tcx>>>, TypeError<TyCtxt<'tcx>>>
sourcepub fn register_member_constraints(
&self,
opaque_type_key: OpaqueTypeKey<TyCtxt<'tcx>>,
concrete_ty: Ty<'tcx>,
span: Span,
)
pub fn register_member_constraints( &self, opaque_type_key: OpaqueTypeKey<TyCtxt<'tcx>>, concrete_ty: Ty<'tcx>, span: Span, )
Given the map opaque_types
containing the opaque
impl Trait
types whose underlying, hidden types are being
inferred, this method adds constraints to the regions
appearing in those underlying hidden types to ensure that they
at least do not refer to random scopes within the current
function. These constraints are not (quite) sufficient to
guarantee that the regions are actually legal values; that
final condition is imposed after region inference is done.
§The Problem
Let’s work through an example to explain how it works. Assume the current function is as follows:
fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
Here, we have two impl Trait
types whose values are being
inferred (the impl Bar<'a>
and the impl Bar<'b>
). Conceptually, this is sugar for a setup where we
define underlying opaque types (Foo1
, Foo2
) and then, in
the return type of foo
, we reference those definitions:
type Foo1<'x> = impl Bar<'x>;
type Foo2<'x> = impl Bar<'x>;
fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
// ^^^^ ^^
// | |
// | args
// def_id
As indicating in the comments above, each of those references
is (in the compiler) basically generic parameters (args
)
applied to the type of a suitable def_id
(which identifies
Foo1
or Foo2
).
Now, at this point in compilation, what we have done is to
replace each of the references (Foo1<'a>
, Foo2<'b>
) with
fresh inference variables C1 and C2. We wish to use the values
of these variables to infer the underlying types of Foo1
and
Foo2
. That is, this gives rise to higher-order (pattern) unification
constraints like:
for<'a> (Foo1<'a> = C1)
for<'b> (Foo1<'b> = C2)
For these equation to be satisfiable, the types C1
and C2
can only refer to a limited set of regions. For example, C1
can only refer to 'static
and 'a
, and C2
can only refer
to 'static
and 'b
. The job of this function is to impose that
constraint.
Up to this point, C1 and C2 are basically just random type
inference variables, and hence they may contain arbitrary
regions. In fact, it is fairly likely that they do! Consider
this possible definition of foo
:
fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
(&*x, &*y)
}
Here, the values for the concrete types of the two impl traits will include inference variables:
&'0 i32
&'1 i32
Ordinarily, the subtyping rules would ensure that these are
sufficiently large. But since impl Bar<'a>
isn’t a specific
type per se, we don’t get such constraints by default. This
is where this function comes into play. It adds extra
constraints to ensure that all the regions which appear in the
inferred type are regions that could validly appear.
This is actually a bit of a tricky constraint in general. We
want to say that each variable (e.g., '0
) can only take on
values that were supplied as arguments to the opaque type
(e.g., 'a
for Foo1<'a>
) or 'static
, which is always in
scope. We don’t have a constraint quite of this kind in the current
region checker.
§The Solution
We generally prefer to make <=
constraints, since they
integrate best into the region solver. To do that, we find the
“minimum” of all the arguments that appear in the args: that
is, some region which is less than all the others. In the case
of Foo1<'a>
, that would be 'a
(it’s the only choice, after
all). Then we apply that as a least bound to the variables
(e.g., 'a <= '0
).
In some cases, there is no minimum. Consider this example:
fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
Here we would report a more complex “in constraint”, like 'r in ['a, 'b, 'static]
(where 'r
is some region appearing in
the hidden type).
§Constrain regions, not the hidden concrete type
Note that generating constraints on each region Rc
is not
the same as generating an outlives constraint on Tc
itself.
For example, if we had a function like this:
fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
(x, y)
}
// Equivalent to:
type FooReturn<'a, T> = impl Foo<'a>;
fn foo<'a, T>(x: &'a u32, y: T) -> FooReturn<'a, T> {
(x, y)
}
then the hidden type Tc
would be (&'0 u32, T)
(where '0
is an inference variable). If we generated a constraint that
Tc: 'a
, then this would incorrectly require that T: 'a
–
but this is not necessary, because the opaque type we
create will be allowed to reference T
. So we only generate a
constraint that '0: 'a
.
Insert a hidden type into the opaque type storage, making sure it hasn’t previously been defined. This does not emit any constraints and it’s the responsibility of the caller to make sure that the item bounds of the opaque are checked.
Insert a hidden type into the opaque type storage, equating it with any previous entries if necessary.
This does not add the item bounds of the opaque as nested obligations. That is only necessary when normalizing the opaque itself, not when getting the opaque type constraints from somewhere else.
sourcepub fn register_region_obligation(&self, obligation: RegionObligation<'tcx>)
pub fn register_region_obligation(&self, obligation: RegionObligation<'tcx>)
Registers that the given region obligation must be resolved
from within the scope of body_id
. These regions are enqueued
and later processed by regionck, when full type information is
available (see region_obligations
field for more
information).
pub fn register_region_obligation_with_cause( &self, sup_type: Ty<'tcx>, sub_region: Region<'tcx>, cause: &ObligationCause<'tcx>, )
sourcepub fn take_registered_region_obligations(&self) -> Vec<RegionObligation<'tcx>>
pub fn take_registered_region_obligations(&self) -> Vec<RegionObligation<'tcx>>
Trait queries just want to pass back type obligations “as is”
sourcepub fn process_registered_region_obligations(
&self,
outlives_env: &OutlivesEnvironment<'tcx>,
deeply_normalize_ty: impl FnMut(Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Ty<'tcx>>>, SubregionOrigin<'tcx>) -> Result<Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Ty<'tcx>>>, NoSolution>,
) -> Result<(), (Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Ty<'tcx>>>, SubregionOrigin<'tcx>)>
pub fn process_registered_region_obligations( &self, outlives_env: &OutlivesEnvironment<'tcx>, deeply_normalize_ty: impl FnMut(Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Ty<'tcx>>>, SubregionOrigin<'tcx>) -> Result<Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Ty<'tcx>>>, NoSolution>, ) -> Result<(), (Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Ty<'tcx>>>, SubregionOrigin<'tcx>)>
Process the region obligations that must be proven (during
regionck
) for the given body_id
, given information about
the region bounds in scope and so forth.
See the region_obligations
field of InferCtxt
for some
comments about how this function fits into the overall expected
flow of the inferencer. The key point is that it is
invoked after all type-inference variables have been bound –
right before lexical region resolution.
sourcepub fn resolve_regions_with_normalize(
&self,
outlives_env: &OutlivesEnvironment<'tcx>,
deeply_normalize_ty: impl Fn(Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Ty<'tcx>>>, SubregionOrigin<'tcx>) -> Result<Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Ty<'tcx>>>, NoSolution>,
) -> Vec<RegionResolutionError<'tcx>>
pub fn resolve_regions_with_normalize( &self, outlives_env: &OutlivesEnvironment<'tcx>, deeply_normalize_ty: impl Fn(Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Ty<'tcx>>>, SubregionOrigin<'tcx>) -> Result<Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Ty<'tcx>>>, NoSolution>, ) -> Vec<RegionResolutionError<'tcx>>
Process the region constraints and return any errors that
result. After this, no more unification operations should be
done – or the compiler will panic – but it is legal to use
resolve_vars_if_possible
as well as fully_resolve
.
If you are in a crate that has access to rustc_trait_selection
,
then it’s probably better to use resolve_regions
,
which knows how to normalize registered region obligations.
sourcepub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx>
pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx>
Obtains (and clears) the current set of region constraints. The inference context is still usable: further unifications will simply add new constraints.
This method is not meant to be used with normal lexical region resolution. Rather, it is used in the NLL mode as a kind of interim hack: basically we run normal type-check and generate region constraints as normal, but then we take them and translate them into the form that the NLL solver understands. See the NLL module for mode details.
sourcepub fn with_region_constraints<R>(
&self,
op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
) -> R
pub fn with_region_constraints<R>( &self, op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, ) -> R
Gives temporary access to the region constraint data.
sourcepub fn projection_ty_to_infer(
&self,
param_env: ParamEnv<'tcx>,
projection_ty: AliasTy<TyCtxt<'tcx>>,
cause: ObligationCause<'tcx>,
recursion_depth: usize,
obligations: &mut Vec<Obligation<'tcx, Predicate<'tcx>>>,
) -> Ty<'tcx>
pub fn projection_ty_to_infer( &self, param_env: ParamEnv<'tcx>, projection_ty: AliasTy<TyCtxt<'tcx>>, cause: ObligationCause<'tcx>, recursion_depth: usize, obligations: &mut Vec<Obligation<'tcx, Predicate<'tcx>>>, ) -> Ty<'tcx>
Instead of normalizing an associated type projection, this function generates an inference variable and registers an obligation that this inference variable must be the result of the given projection. This allows us to proceed with projections while they cannot be resolved yet due to missing information or simply due to the lack of access to the trait resolution machinery.
sourcepub fn instantiate_ty_var<R>(
&self,
relation: &mut R,
target_is_expected: bool,
target_vid: TyVid,
instantiation_variance: Variance,
source_ty: Ty<'tcx>,
) -> Result<(), TypeError<TyCtxt<'tcx>>>where
R: PredicateEmittingRelation<InferCtxt<'tcx>>,
pub fn instantiate_ty_var<R>(
&self,
relation: &mut R,
target_is_expected: bool,
target_vid: TyVid,
instantiation_variance: Variance,
source_ty: Ty<'tcx>,
) -> Result<(), TypeError<TyCtxt<'tcx>>>where
R: PredicateEmittingRelation<InferCtxt<'tcx>>,
The idea is that we should ensure that the type variable target_vid
is equal to, a subtype of, or a supertype of source_ty
.
For this, we will instantiate target_vid
with a generalized version
of source_ty
. Generalization introduces other inference variables wherever
subtyping could occur. This also does the occurs checks, detecting whether
instantiating target_vid
would result in a cyclic type. We eagerly error
in this case.
This is not expected to be used anywhere except for an implementation of
TypeRelation
. Do not use this, and instead please use At::eq
, for all
other usecases (i.e. setting the value of a type var).
sourcepub fn enter_forall_and_leak_universe<T>(
&self,
binder: Binder<TyCtxt<'tcx>, T>,
) -> T
pub fn enter_forall_and_leak_universe<T>( &self, binder: Binder<TyCtxt<'tcx>, T>, ) -> T
Replaces all bound variables (lifetimes, types, and constants) bound by
binder
with placeholder variables in a new universe. This means that the
new placeholders can only be named by inference variables created after
this method has been called.
This is the first step of checking subtyping when higher-ranked things are involved. For more details visit the relevant sections of the rustc dev guide.
fn enter_forall
should be preferred over this method.
sourcepub fn enter_forall<T, U>(
&self,
forall: Binder<TyCtxt<'tcx>, T>,
f: impl FnOnce(T) -> U,
) -> U
pub fn enter_forall<T, U>( &self, forall: Binder<TyCtxt<'tcx>, T>, f: impl FnOnce(T) -> U, ) -> U
Replaces all bound variables (lifetimes, types, and constants) bound by
binder
with placeholder variables in a new universe and then calls the
closure f
with the instantiated value. The new placeholders can only be
named by inference variables created inside of the closure f
or afterwards.
This is the first step of checking subtyping when higher-ranked things are involved. For more details visit the relevant sections of the rustc dev guide.
This method should be preferred over fn enter_forall_and_leak_universe
.
sourcepub fn leak_check(
&self,
outer_universe: UniverseIndex,
only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>,
) -> Result<(), TypeError<TyCtxt<'tcx>>>
pub fn leak_check( &self, outer_universe: UniverseIndex, only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, ) -> Result<(), TypeError<TyCtxt<'tcx>>>
See RegionConstraintCollector::leak_check. We only check placeholder
leaking into outer_universe
, i.e. placeholders which cannot be named by that
universe.
sourcepub fn fudge_inference_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
pub fn fudge_inference_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
This rather funky routine is used while processing expected
types. What happens here is that we want to propagate a
coercion through the return type of a fn to its
argument. Consider the type of Option::Some
, which is
basically for<T> fn(T) -> Option<T>
. So if we have an
expression Some(&[1, 2, 3])
, and that has the expected type
Option<&[u32]>
, we would like to type check &[1, 2, 3]
with the expectation of &[u32]
. This will cause us to coerce
from &[u32; 3]
to &[u32]
and make the users life more
pleasant.
The way we do this is using fudge_inference_if_ok
. What the
routine actually does is to start a snapshot and execute the
closure f
. In our example above, what this closure will do
is to unify the expectation (Option<&[u32]>
) with the actual
return type (Option<?T>
, where ?T
represents the variable
instantiated for T
). This will cause ?T
to be unified
with &?a [u32]
, where ?a
is a fresh lifetime variable. The
input type (?T
) is then returned by f()
.
At this point, fudge_inference_if_ok
will normalize all type
variables, converting ?T
to &?a [u32]
and end the
snapshot. The problem is that we can’t just return this type
out, because it references the region variable ?a
, and that
region variable was popped when we popped the snapshot.
So what we do is to keep a list (region_vars
, in the code below)
of region variables created during the snapshot (here, ?a
). We
fold the return value and replace any such regions with a new
region variable (e.g., ?b
) and return the result (&?b [u32]
).
This can then be used as the expectation for the fn argument.
The important point here is that, for soundness purposes, the
regions in question are not particularly important. We will
use the expected types to guide coercions, but we will still
type-check the resulting types from those coercions against
the actual types (?T
, Option<?T>
) – and remember that
after the snapshot is popped, the variable ?T
is no longer
unified.
pub fn in_snapshot(&self) -> bool
pub fn num_open_snapshots(&self) -> usize
sourcepub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
Execute f
and commit the bindings if closure f
returns Ok(_)
.
sourcepub fn probe<R, F>(&self, f: F) -> Rwhere
F: FnOnce(&CombinedSnapshot<'tcx>) -> R,
pub fn probe<R, F>(&self, f: F) -> Rwhere
F: FnOnce(&CombinedSnapshot<'tcx>) -> R,
Execute f
then unroll any bindings it creates.
sourcepub fn region_constraints_added_in_snapshot(
&self,
snapshot: &CombinedSnapshot<'tcx>,
) -> bool
pub fn region_constraints_added_in_snapshot( &self, snapshot: &CombinedSnapshot<'tcx>, ) -> bool
Scan the constraints produced since snapshot
and check whether
we added any region constraints.
pub fn opaque_types_added_in_snapshot( &self, snapshot: &CombinedSnapshot<'tcx>, ) -> bool
pub fn dcx(&self) -> DiagCtxtHandle<'_>
pub fn defining_opaque_types(&self) -> &'tcx RawList<(), LocalDefId>
pub fn next_trait_solver(&self) -> bool
pub fn freshen<T>(&self, t: T) -> Twhere
T: TypeFoldable<TyCtxt<'tcx>>,
sourcepub fn type_var_origin(&self, vid: TyVid) -> TypeVariableOrigin
pub fn type_var_origin(&self, vid: TyVid) -> TypeVariableOrigin
Returns the origin of the type variable identified by vid
.
No attempt is made to resolve vid
to its root variable.
sourcepub fn const_var_origin(&self, vid: ConstVid) -> Option<ConstVariableOrigin>
pub fn const_var_origin(&self, vid: ConstVid) -> Option<ConstVariableOrigin>
Returns the origin of the const variable identified by vid
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx>
pub fn unresolved_variables(&self) -> Vec<Ty<'tcx>>
pub fn unsolved_effects(&self) -> Vec<Const<'tcx>>
pub fn sub_regions( &self, origin: SubregionOrigin<'tcx>, a: Region<'tcx>, b: Region<'tcx>, )
sourcepub fn member_constraint(
&self,
key: OpaqueTypeKey<TyCtxt<'tcx>>,
definition_span: Span,
hidden_ty: Ty<'tcx>,
region: Region<'tcx>,
in_regions: Rc<Vec<Region<'tcx>>>,
)
pub fn member_constraint( &self, key: OpaqueTypeKey<TyCtxt<'tcx>>, definition_span: Span, hidden_ty: Ty<'tcx>, region: Region<'tcx>, in_regions: Rc<Vec<Region<'tcx>>>, )
Require that the region r
be equal to one of the regions in
the set regions
.
sourcepub fn coerce_predicate(
&self,
cause: &ObligationCause<'tcx>,
param_env: ParamEnv<'tcx>,
predicate: Binder<TyCtxt<'tcx>, CoercePredicate<TyCtxt<'tcx>>>,
) -> Result<Result<InferOk<'tcx, ()>, TypeError<TyCtxt<'tcx>>>, (TyVid, TyVid)>
pub fn coerce_predicate( &self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, predicate: Binder<TyCtxt<'tcx>, CoercePredicate<TyCtxt<'tcx>>>, ) -> Result<Result<InferOk<'tcx, ()>, TypeError<TyCtxt<'tcx>>>, (TyVid, TyVid)>
Processes a Coerce
predicate from the fulfillment context.
This is NOT the preferred way to handle coercion, which is to
invoke FnCtxt::coerce
or a similar method (see coercion.rs
).
This method here is actually a fallback that winds up being
invoked when FnCtxt::coerce
encounters unresolved type variables
and records a coercion predicate. Presently, this method is equivalent
to subtype_predicate
– that is, “coercing” a
to b
winds up
actually requiring a <: b
. This is of course a valid coercion,
but it’s not as flexible as FnCtxt::coerce
would be.
(We may refactor this in the future, but there are a number of
practical obstacles. Among other things, FnCtxt::coerce
presently
records adjustments that are required on the HIR in order to perform
the coercion, and we don’t currently have a way to manage that.)
pub fn subtype_predicate( &self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, predicate: Binder<TyCtxt<'tcx>, SubtypePredicate<TyCtxt<'tcx>>>, ) -> Result<Result<InferOk<'tcx, ()>, TypeError<TyCtxt<'tcx>>>, (TyVid, TyVid)>
pub fn region_outlives_predicate( &self, cause: &ObligationCause<'tcx>, predicate: Binder<TyCtxt<'tcx>, OutlivesPredicate<TyCtxt<'tcx>, Region<'tcx>>>, )
sourcepub fn num_ty_vars(&self) -> usize
pub fn num_ty_vars(&self) -> usize
Number of type variables created so far.
pub fn next_ty_var(&self, span: Span) -> Ty<'tcx>
pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx>
pub fn next_ty_var_id_in_universe( &self, span: Span, universe: UniverseIndex, ) -> TyVid
pub fn next_ty_var_in_universe( &self, span: Span, universe: UniverseIndex, ) -> Ty<'tcx>
pub fn next_const_var(&self, span: Span) -> Const<'tcx>
pub fn next_const_var_with_origin( &self, origin: ConstVariableOrigin, ) -> Const<'tcx>
pub fn next_const_var_in_universe( &self, span: Span, universe: UniverseIndex, ) -> Const<'tcx>
pub fn next_int_var(&self) -> Ty<'tcx>
pub fn next_float_var(&self) -> Ty<'tcx>
sourcepub fn next_region_var(&self, origin: RegionVariableOrigin) -> Region<'tcx>
pub fn next_region_var(&self, origin: RegionVariableOrigin) -> Region<'tcx>
Creates a fresh region variable with the next available index. The variable will be created in the maximum universe created thus far, allowing it to name any region created thus far.
sourcepub fn next_region_var_in_universe(
&self,
origin: RegionVariableOrigin,
universe: UniverseIndex,
) -> Region<'tcx>
pub fn next_region_var_in_universe( &self, origin: RegionVariableOrigin, universe: UniverseIndex, ) -> Region<'tcx>
Creates a fresh region variable with the next available index
in the given universe; typically, you can use
next_region_var
and just use the maximal universe.
sourcepub fn universe_of_region(&self, r: Region<'tcx>) -> UniverseIndex
pub fn universe_of_region(&self, r: Region<'tcx>) -> UniverseIndex
Return the universe that the region r
was created in. For
most regions (e.g., 'static
, named regions from the user,
etc) this is the root universe U0. For inference variables or
placeholders, however, it will return the universe which they
are associated.
sourcepub fn num_region_vars(&self) -> usize
pub fn num_region_vars(&self) -> usize
Number of region variables created so far.
sourcepub fn next_nll_region_var(
&self,
origin: NllRegionVariableOrigin,
) -> Region<'tcx>
pub fn next_nll_region_var( &self, origin: NllRegionVariableOrigin, ) -> Region<'tcx>
Just a convenient wrapper of next_region_var
for using during NLL.
sourcepub fn next_nll_region_var_in_universe(
&self,
origin: NllRegionVariableOrigin,
universe: UniverseIndex,
) -> Region<'tcx>
pub fn next_nll_region_var_in_universe( &self, origin: NllRegionVariableOrigin, universe: UniverseIndex, ) -> Region<'tcx>
Just a convenient wrapper of next_region_var
for using during NLL.
pub fn var_for_def( &self, span: Span, param: &GenericParamDef, ) -> GenericArg<'tcx>
pub fn var_for_effect(&self, param: &GenericParamDef) -> GenericArg<'tcx>
sourcepub fn fresh_args_for_item(
&self,
span: Span,
def_id: DefId,
) -> &'tcx RawList<(), GenericArg<'tcx>>
pub fn fresh_args_for_item( &self, span: Span, def_id: DefId, ) -> &'tcx RawList<(), GenericArg<'tcx>>
Given a set of generics defined on a type or impl, returns the generic parameters mapping each type/region parameter to a fresh inference variable.
sourcepub fn tainted_by_errors(&self) -> Option<ErrorGuaranteed>
pub fn tainted_by_errors(&self) -> Option<ErrorGuaranteed>
Returns true
if errors have been reported since this infcx was
created. This is sometimes used as a heuristic to skip
reporting errors that often occur as a result of earlier
errors, but where it’s hard to be 100% sure (e.g., unresolved
inference variables, regionck errors).
sourcepub fn set_tainted_by_errors(&self, e: ErrorGuaranteed)
pub fn set_tainted_by_errors(&self, e: ErrorGuaranteed)
Set the “tainted by errors” flag to true. We call this when we observe an error from a prior pass.
pub fn region_var_origin(&self, vid: RegionVid) -> RegionVariableOrigin
sourcepub fn get_region_var_origins(&self) -> IndexVec<RegionVid, RegionVariableInfo>
pub fn get_region_var_origins(&self) -> IndexVec<RegionVid, RegionVariableInfo>
Clone the list of variable regions. This is used only during NLL processing to put the set of region variables into the NLL region context.
pub fn take_opaque_types( &self, ) -> IndexMap<OpaqueTypeKey<TyCtxt<'tcx>>, OpaqueTypeDecl<'tcx>, BuildHasherDefault<FxHasher>>
pub fn clone_opaque_types( &self, ) -> IndexMap<OpaqueTypeKey<TyCtxt<'tcx>>, OpaqueTypeDecl<'tcx>, BuildHasherDefault<FxHasher>>
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String
sourcepub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, UniverseIndex>
pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, UniverseIndex>
If TyVar(vid)
resolves to a type, return that type. Else, return the
universe index of TyVar(vid)
.
pub fn shallow_resolve(&self, ty: Ty<'tcx>) -> Ty<'tcx>
pub fn shallow_resolve_const(&self, ct: Const<'tcx>) -> Const<'tcx>
pub fn root_var(&self, var: TyVid) -> TyVid
pub fn root_const_var(&self, var: ConstVid) -> ConstVid
pub fn root_effect_var(&self, var: EffectVid) -> EffectVid
sourcepub fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx>
pub fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx>
Resolves an int var to a rigid int type, if it was constrained to one, or else the root int var in the unification table.
sourcepub fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx>
pub fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx>
Resolves a float var to a rigid int type, if it was constrained to one, or else the root float var in the unification table.
sourcepub fn resolve_vars_if_possible<T>(&self, value: T) -> Twhere
T: TypeFoldable<TyCtxt<'tcx>>,
pub fn resolve_vars_if_possible<T>(&self, value: T) -> Twhere
T: TypeFoldable<TyCtxt<'tcx>>,
Where possible, replaces type/const variables in
value
with their final value. Note that region variables
are unaffected. If a type/const variable has not been unified, it
is left as is. This is an idempotent operation that does
not affect inference state in any way and so you can do it
at will.
pub fn resolve_numeric_literals_with_default<T>(&self, value: T) -> Twhere
T: TypeFoldable<TyCtxt<'tcx>>,
pub fn probe_const_var( &self, vid: ConstVid, ) -> Result<Const<'tcx>, UniverseIndex>
pub fn probe_effect_var(&self, vid: EffectVid) -> Option<Const<'tcx>>
sourcepub fn fully_resolve<T>(&self, value: T) -> Result<T, FixupError>where
T: TypeFoldable<TyCtxt<'tcx>>,
pub fn fully_resolve<T>(&self, value: T) -> Result<T, FixupError>where
T: TypeFoldable<TyCtxt<'tcx>>,
Attempts to resolve all type/region/const variables in
value
. Region inference must have been run already (e.g.,
by calling resolve_regions_and_report_errors
). If some
variable was never unified, an Err
results.
This method is idempotent, but it not typically not invoked except during the writeback phase.
pub fn instantiate_binder_with_fresh_vars<T>( &self, span: Span, lbrct: BoundRegionConversionTime, value: Binder<TyCtxt<'tcx>, T>, ) -> T
sourcepub fn closure_kind(&self, closure_ty: Ty<'tcx>) -> Option<ClosureKind>
pub fn closure_kind(&self, closure_ty: Ty<'tcx>) -> Option<ClosureKind>
Obtains the latest type of the given closure; this may be a
closure in the current function, in which case its
ClosureKind
may not yet be known.
pub fn universe(&self) -> UniverseIndex
sourcepub fn create_next_universe(&self) -> UniverseIndex
pub fn create_next_universe(&self) -> UniverseIndex
Creates and return a fresh universe that extends all previous
universes. Updates self.universe
to that new universe.
pub fn try_const_eval_resolve( &self, param_env: ParamEnv<'tcx>, unevaluated: UnevaluatedConst<TyCtxt<'tcx>>, span: Span, ) -> Result<Const<'tcx>, ErrorHandled>
sourcepub fn const_eval_resolve(
&self,
param_env: ParamEnv<'tcx>,
unevaluated: UnevaluatedConst<TyCtxt<'tcx>>,
span: Span,
) -> Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>
pub fn const_eval_resolve( &self, param_env: ParamEnv<'tcx>, unevaluated: UnevaluatedConst<TyCtxt<'tcx>>, span: Span, ) -> Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>
Resolves and evaluates a constant.
The constant can be located on a trait like <A as B>::C
, in which case the given
generic parameters and environment are used to resolve the constant. Alternatively if the
constant has generic parameters in scope the instantiations are used to evaluate the value
of the constant. For example in fn foo<T>() { let _ = [0; bar::<T>()]; }
the repeat count
constant bar::<T>()
requires a instantiation for T
, if the instantiation for T
is
still too generic for the constant to be evaluated then Err(ErrorHandled::TooGeneric)
is
returned.
This handles inferences variables within both param_env
and args
by
performing the operation on their respective canonical forms.
sourcepub fn is_ty_infer_var_definitely_unchanged<'a>(
&'a self,
) -> impl Fn(TyOrConstInferVar) + Captures<'tcx> + 'a
pub fn is_ty_infer_var_definitely_unchanged<'a>( &'a self, ) -> impl Fn(TyOrConstInferVar) + Captures<'tcx> + 'a
The returned function is used in a fast path. If it returns true
the variable is
unchanged, false
indicates that the status is unknown.
sourcepub fn ty_or_const_infer_var_changed(
&self,
infer_var: TyOrConstInferVar,
) -> bool
pub fn ty_or_const_infer_var_changed( &self, infer_var: TyOrConstInferVar, ) -> bool
ty_or_const_infer_var_changed
is equivalent to one of these two:
shallow_resolve(ty) != ty
(wherety.kind = ty::Infer(_)
)shallow_resolve(ct) != ct
(wherect.kind = ty::ConstKind::Infer(_)
)
However, ty_or_const_infer_var_changed
is more efficient. It’s always
inlined, despite being large, because it has only two call sites that
are extremely hot (both in traits::fulfill
’s checking of stalled_on
inference variables), and it handles both Ty
and ty::Const
without
having to resort to storing full GenericArg
s in stalled_on
.
sourcepub fn attach_obligation_inspector(
&self,
inspector: fn(_: &InferCtxt<'tcx>, _: &Obligation<'tcx, Predicate<'tcx>>, _: Result<Certainty, NoSolution>),
)
pub fn attach_obligation_inspector( &self, inspector: fn(_: &InferCtxt<'tcx>, _: &Obligation<'tcx, Predicate<'tcx>>, _: Result<Certainty, NoSolution>), )
Attach a callback to be invoked on each root obligation evaluated in the new trait solver.
sourcepub fn find_block_span(&self, block: &'tcx Block<'tcx>) -> Span
pub fn find_block_span(&self, block: &'tcx Block<'tcx>) -> Span
Given a hir::Block
, get the span of its last expression or
statement, peeling off any inner blocks.
sourcepub fn find_block_span_from_hir_id(&self, hir_id: HirId) -> Span
pub fn find_block_span_from_hir_id(&self, hir_id: HirId) -> Span
Given a hir::HirId
for a block, get the span of its last expression
or statement, peeling off any inner blocks.
Trait Implementations§
Auto Trait Implementations§
impl<'a, 'tcx> !Freeze for ProbeContext<'a, 'tcx>
impl<'a, 'tcx> !RefUnwindSafe for ProbeContext<'a, 'tcx>
impl<'a, 'tcx> !Send for ProbeContext<'a, 'tcx>
impl<'a, 'tcx> !Sync for ProbeContext<'a, 'tcx>
impl<'a, 'tcx> Unpin for ProbeContext<'a, 'tcx>
impl<'a, 'tcx> !UnwindSafe for ProbeContext<'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
source§impl<T, R> CollectAndApply<T, R> for T
impl<T, R> CollectAndApply<T, R> for T
source§impl<T> Filterable for T
impl<T> Filterable for T
source§fn filterable(
self,
filter_name: &'static str,
) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>
fn filterable( self, filter_name: &'static str, ) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§impl<P> IntoQueryParam<P> for P
impl<P> IntoQueryParam<P> for P
fn into_query_param(self) -> P
source§impl<T> MaybeResult<T> for T
impl<T> MaybeResult<T> for T
source§impl<I, T, U> Upcast<I, U> for Twhere
U: UpcastFrom<I, T>,
impl<I, T, U> Upcast<I, U> for Twhere
U: UpcastFrom<I, T>,
source§impl<I, T> UpcastFrom<I, T> for T
impl<I, T> UpcastFrom<I, T> for T
fn upcast_from(from: T, _tcx: I) -> T
source§impl<Tcx, T> Value<Tcx> for Twhere
Tcx: DepContext,
impl<Tcx, T> Value<Tcx> for Twhere
Tcx: DepContext,
default fn from_cycle_error( tcx: Tcx, cycle_error: &CycleError, _guar: ErrorGuaranteed, ) -> T
source§impl<T> WithSubscriber for T
impl<T> WithSubscriber for T
source§fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
source§fn with_current_subscriber(self) -> WithDispatch<Self>
fn with_current_subscriber(self) -> WithDispatch<Self>
impl<'a, T> Captures<'a> for Twhere
T: ?Sized,
impl<T> ErasedDestructor for Twhere
T: 'static,
impl<T> MaybeSendSync for 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: 256 bytes