pub 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 initial expected_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 an if with no else. In that case, invoke coerce_forced_unit().
    • coerce() and coerce_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 be err.
    • Invoking coerce() may cause us to go and adjust the “adjustments” on previously coerced expressions.
  • 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.

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>

source

pub 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.

source

pub 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.

source

fn make( expected_ty: Ty<'tcx>, expressions: Expressions<'tcx, 'exprs, E> ) -> Self

source

pub 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.

source

pub 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.

source

pub 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.

source

pub fn coerce_forced_unit<'a>( &mut self, fcx: &FnCtxt<'a, 'tcx>, cause: &ObligationCause<'tcx>, augment_error: impl FnOnce(&mut DiagnosticBuilder<'_>), 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 ;).

source

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 DiagnosticBuilder<'_>), 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.

source

fn note_unreachable_loop_return( &self, err: &mut DiagnosticBuilder<'_>, tcx: TyCtxt<'tcx>, expr: &Expr<'tcx>, ret_exprs: &Vec<&'tcx Expr<'tcx>>, ty: Ty<'tcx> )

source

fn report_return_mismatched_types<'a>( &self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, ty_err: TypeError<'tcx>, fcx: &FnCtxt<'a, 'tcx>, id: HirId, expression: Option<&'tcx Expr<'tcx>>, blk_id: Option<HirId> ) -> DiagnosticBuilder<'a>

source

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.

source

pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx>

Auto Trait Implementations§

§

impl<'tcx, 'exprs, E> DynSend for CoerceMany<'tcx, 'exprs, E>
where E: DynSync,

§

impl<'tcx, 'exprs, E> DynSync for CoerceMany<'tcx, 'exprs, E>
where E: DynSync,

§

impl<'tcx, 'exprs, E> !RefUnwindSafe for CoerceMany<'tcx, 'exprs, E>

§

impl<'tcx, 'exprs, E> Send for CoerceMany<'tcx, 'exprs, E>
where E: Sync,

§

impl<'tcx, 'exprs, E> Sync for CoerceMany<'tcx, 'exprs, E>
where E: Sync,

§

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> Aligned for T

source§

const ALIGN: Alignment = _

Alignment of Self.
source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T, R> CollectAndApply<T, R> for T

source§

fn collect_and_apply<I, F>(iter: I, f: F) -> R
where I: Iterator<Item = T>, F: FnOnce(&[T]) -> R,

Equivalent to f(&iter.collect::<Vec<_>>()).

§

type Output = R

§

impl<T> Filterable for T

§

fn filterable( self, filter_name: &'static str ) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>

Creates a filterable data provider with the given name for debugging. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<P> IntoQueryParam<P> for P

source§

impl<T> MaybeResult<T> for T

§

type Error = !

source§

fn from(_: Result<T, <T as MaybeResult<T>>::Error>) -> T

source§

fn to_result(self) -> Result<T, <T as MaybeResult<T>>::Error>

§

impl<T> Pointable for T

§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<'tcx, T> ToPredicate<'tcx, T> for T

source§

fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> T

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<Tcx, T> Value<Tcx> for T
where Tcx: DepContext,

source§

default fn from_cycle_error( tcx: Tcx, cycle_error: &CycleError, _guar: ErrorGuaranteed ) -> T

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

impl<'a, T> Captures<'a> for T
where T: ?Sized,

§

impl<T> ErasedDestructor for T
where T: 'static,

§

impl<T> MaybeSendSync for T
where T: Send + Sync,

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