pub(crate) struct CoerceMany<'tcx, 'exprs, E: AsCoercionSite> {
expected_ty: Ty<'tcx>,
final_ty: Option<Ty<'tcx>>,
expressions: Expressions<'tcx, 'exprs, E>,
pushed: usize,
}
Expand description
CoerceMany encapsulates the pattern you should use when you have
many expressions that are all getting coerced to a common
type. This arises, for example, when you have a match (the result
of each arm is coerced to a common type). It also arises in less
obvious places, such as when you have many break foo
expressions
that target the same loop, or the various return
expressions in
a function.
The basic protocol is as follows:
- Instantiate the
CoerceMany
with an initialexpected_ty
. This will also serve as the “starting LUB”. The expectation is that this type is something which all of the expressions must be coercible to. Use a fresh type variable if needed. - For each expression whose result is to be coerced, invoke
coerce()
with.- In some cases we wish to coerce “non-expressions” whose types are implicitly
unit. This happens for example if you have a
break
with no expression, or anif
with noelse
. In that case, invokecoerce_forced_unit()
. coerce()
andcoerce_forced_unit()
may report errors. They hide this from you so that you don’t have to worry your pretty head about it. But if an error is reported, the final type will beerr
.- Invoking
coerce()
may cause us to go and adjust the “adjustments” on previously coerced expressions.
- In some cases we wish to coerce “non-expressions” whose types are implicitly
unit. This happens for example if you have a
- When all done, invoke
complete()
. This will return the LUB of all your expressions.- WARNING: I don’t believe this final type is guaranteed to be
related to your initial
expected_ty
in any particular way, although it will typically be a subtype, so you should check it. - Invoking
complete()
may cause us to go and adjust the “adjustments” on previously coerced expressions.
- WARNING: I don’t believe this final type is guaranteed to be
related to your initial
Example:
let mut coerce = CoerceMany::new(expected_ty);
for expr in exprs {
let expr_ty = fcx.check_expr_with_expectation(expr, expected);
coerce.coerce(fcx, &cause, expr, expr_ty);
}
let final_ty = coerce.complete(fcx);
Fields§
§expected_ty: Ty<'tcx>
§final_ty: Option<Ty<'tcx>>
§expressions: Expressions<'tcx, 'exprs, E>
§pushed: usize
Implementations§
source§impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E>
impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E>
sourcepub(crate) fn new(expected_ty: Ty<'tcx>) -> Self
pub(crate) fn new(expected_ty: Ty<'tcx>) -> Self
The usual case; collect the set of expressions dynamically.
If the full set of coercion sites is known before hand,
consider with_coercion_sites()
instead to avoid allocation.
sourcepub(crate) fn with_coercion_sites(
expected_ty: Ty<'tcx>,
coercion_sites: &'exprs [E],
) -> Self
pub(crate) fn with_coercion_sites( expected_ty: Ty<'tcx>, coercion_sites: &'exprs [E], ) -> Self
As an optimization, you can create a CoerceMany
with a
preexisting slice of expressions. In this case, you are
expected to pass each element in the slice to coerce(...)
in
order. This is used with arrays in particular to avoid
needlessly cloning the slice.
fn make( expected_ty: Ty<'tcx>, expressions: Expressions<'tcx, 'exprs, E>, ) -> Self
sourcepub(crate) fn expected_ty(&self) -> Ty<'tcx>
pub(crate) fn expected_ty(&self) -> Ty<'tcx>
Returns the “expected type” with which this coercion was constructed. This represents the “downward propagated” type that was given to us at the start of typing whatever construct we are typing (e.g., the match expression).
Typically, this is used as the expected type when type-checking each of the alternative expressions whose types we are trying to merge.
sourcepub(crate) fn merged_ty(&self) -> Ty<'tcx>
pub(crate) fn merged_ty(&self) -> Ty<'tcx>
Returns the current “merged type”, representing our best-guess
at the LUB of the expressions we’ve seen so far (if any). This
isn’t final until you call self.complete()
, which will return
the merged type.
sourcepub(crate) fn coerce<'a>(
&mut self,
fcx: &FnCtxt<'a, 'tcx>,
cause: &ObligationCause<'tcx>,
expression: &'tcx Expr<'tcx>,
expression_ty: Ty<'tcx>,
)
pub(crate) fn coerce<'a>( &mut self, fcx: &FnCtxt<'a, 'tcx>, cause: &ObligationCause<'tcx>, expression: &'tcx Expr<'tcx>, expression_ty: Ty<'tcx>, )
Indicates that the value generated by expression
, which is
of type expression_ty
, is one of the possibilities that we
could coerce from. This will record expression
, and later
calls to coerce
may come back and add adjustments and things
if necessary.
sourcepub(crate) fn coerce_forced_unit<'a>(
&mut self,
fcx: &FnCtxt<'a, 'tcx>,
cause: &ObligationCause<'tcx>,
augment_error: impl FnOnce(&mut Diag<'_>),
label_unit_as_expected: bool,
)
pub(crate) fn coerce_forced_unit<'a>( &mut self, fcx: &FnCtxt<'a, 'tcx>, cause: &ObligationCause<'tcx>, augment_error: impl FnOnce(&mut Diag<'_>), label_unit_as_expected: bool, )
Indicates that one of the inputs is a “forced unit”. This
occurs in a case like if foo { ... };
, where the missing else
generates a “forced unit”. Another example is a loop { break; }
, where the break
has no argument expression. We treat
these cases slightly differently for error-reporting
purposes. Note that these tend to correspond to cases where
the ()
expression is implicit in the source, and hence we do
not take an expression argument.
The augment_error
gives you a chance to extend the error
message, in case any results (e.g., we use this to suggest
removing a ;
).
sourcepub(crate) fn coerce_inner<'a>(
&mut self,
fcx: &FnCtxt<'a, 'tcx>,
cause: &ObligationCause<'tcx>,
expression: Option<&'tcx Expr<'tcx>>,
expression_ty: Ty<'tcx>,
augment_error: impl FnOnce(&mut Diag<'_>),
label_expression_as_expected: bool,
)
pub(crate) fn coerce_inner<'a>( &mut self, fcx: &FnCtxt<'a, 'tcx>, cause: &ObligationCause<'tcx>, expression: Option<&'tcx Expr<'tcx>>, expression_ty: Ty<'tcx>, augment_error: impl FnOnce(&mut Diag<'_>), label_expression_as_expected: bool, )
The inner coercion “engine”. If expression
is None
, this
is a forced-unit case, and hence expression_ty
must be
Nil
.
fn suggest_boxing_tail_for_return_position_impl_trait( &self, fcx: &FnCtxt<'_, 'tcx>, err: &mut Diag<'_>, rpit_def_id: LocalDefId, a_ty: Ty<'tcx>, b_ty: Ty<'tcx>, arm_spans: impl Iterator<Item = Span>, )
fn report_return_mismatched_types<'infcx>( &self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, ty_err: TypeError<'tcx>, fcx: &'infcx FnCtxt<'_, 'tcx>, block_or_return_id: HirId, expression: Option<&'tcx Expr<'tcx>>, ) -> Diag<'infcx>
sourcefn is_return_ty_definitely_unsized(&self, fcx: &FnCtxt<'_, 'tcx>) -> bool
fn is_return_ty_definitely_unsized(&self, fcx: &FnCtxt<'_, 'tcx>) -> bool
Checks whether the return type is unsized via an obligation, which makes
sure we consider dyn Trait: Sized
where clauses, which are trivially
false but technically valid for typeck.
pub(crate) fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx>
Auto Trait Implementations§
impl<'tcx, 'exprs, E> Freeze for CoerceMany<'tcx, 'exprs, E>
impl<'tcx, 'exprs, E> !RefUnwindSafe for CoerceMany<'tcx, 'exprs, E>
impl<'tcx, 'exprs, E> !Send for CoerceMany<'tcx, 'exprs, E>
impl<'tcx, 'exprs, E> !Sync for CoerceMany<'tcx, 'exprs, E>
impl<'tcx, 'exprs, E> Unpin for CoerceMany<'tcx, 'exprs, E>
impl<'tcx, 'exprs, E> !UnwindSafe for CoerceMany<'tcx, 'exprs, E>
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: 48 bytes