1use rustc_middle::traits::ObligationCause;
2use rustc_middle::ty::{self, Ty};
3use rustc_span::Span;
45use super::Expectation::*;
6use super::FnCtxt;
78/// When type-checking an expression, we propagate downward
9/// whatever type hint we are able in the form of an `Expectation`.
10#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for Expectation<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for Expectation<'tcx> {
#[inline]
fn clone(&self) -> Expectation<'tcx> {
let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for Expectation<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Expectation::NoExpectation =>
::core::fmt::Formatter::write_str(f, "NoExpectation"),
Expectation::ExpectHasType(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ExpectHasType", &__self_0),
Expectation::ExpectCastableToType(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ExpectCastableToType", &__self_0),
Expectation::ExpectRvalueLikeUnsized(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ExpectRvalueLikeUnsized", &__self_0),
}
}
}Debug)]
11pub(crate) enum Expectation<'tcx> {
12/// We know nothing about what type this expression should have.
13NoExpectation,
1415/// This expression should have the type given (or some subtype).
16ExpectHasType(Ty<'tcx>),
1718/// This expression will be cast to the `Ty`.
19ExpectCastableToType(Ty<'tcx>),
2021/// This rvalue expression will be wrapped in `&` or `Box` and coerced
22 /// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
23ExpectRvalueLikeUnsized(Ty<'tcx>),
24}
2526impl<'a, 'tcx> Expectation<'tcx> {
27// Disregard "castable to" expectations because they
28 // can lead us astray. Consider for example `if cond
29 // {22} else {c} as u8` -- if we propagate the
30 // "castable to u8" constraint to 22, it will pick the
31 // type 22u8, which is overly constrained (c might not
32 // be a u8). In effect, the problem is that the
33 // "castable to" expectation is not the tightest thing
34 // we can say, so we want to drop it in this case.
35 // The tightest thing we can say is "must unify with
36 // else branch". Note that in the case of a "has type"
37 // constraint, this limitation does not hold.
3839 // If the expected type is just a type variable, then don't use
40 // an expected type. Otherwise, we might write parts of the type
41 // when checking the 'then' block which are incompatible with the
42 // 'else' branch.
43pub(super) fn try_structurally_resolve_and_adjust_for_branches(
44&self,
45 fcx: &FnCtxt<'a, 'tcx>,
46 ) -> Expectation<'tcx> {
47match *self {
48ExpectHasType(ety) => {
49let ety = fcx.resolve_vars_with_obligations(ety);
50if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
51 }
52ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety),
53_ => NoExpectation,
54 }
55 }
5657/// Provides an expectation for an rvalue expression given an *optional*
58 /// hint, which is not required for type safety (the resulting type might
59 /// be checked higher up, as is the case with `&expr` and `box expr`), but
60 /// is useful in determining the concrete type.
61 ///
62 /// The primary use case is where the expected type is a wide pointer,
63 /// like `&[isize]`. For example, consider the following statement:
64 ///
65 /// let x: &[isize] = &[1, 2, 3];
66 ///
67 /// In this case, the expected type for the `&[1, 2, 3]` expression is
68 /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
69 /// expectation `ExpectHasType([isize])`, that would be too strong --
70 /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
71 /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
72 /// to the type `&[isize]`. Therefore, we propagate this more limited hint,
73 /// which still is useful, because it informs integer literals and the like.
74 /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
75 /// for examples of where this comes up,.
76pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
77let span = match ty.kind() {
78 ty::Adt(adt_def, _) => fcx.tcx.def_span(adt_def.did()),
79_ => fcx.tcx.def_span(fcx.body_id),
80 };
81let cause = ObligationCause::misc(span, fcx.body_id);
8283// FIXME: This is not right, even in the old solver...
84match fcx.tcx.struct_tail_raw(ty, &cause, |ty| ty, || {}).kind() {
85 ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty),
86_ => ExpectHasType(ty),
87 }
88 }
8990/// Resolves `expected` by a single level if it is a variable. If
91 /// there is no expected type or resolution is not possible (e.g.,
92 /// no constraints yet present), just returns `self`.
93fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
94match self {
95NoExpectation => NoExpectation,
96ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(t)),
97ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(t)),
98ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(t)),
99 }
100 }
101102pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
103match self.resolve(fcx) {
104NoExpectation => None,
105ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty),
106 }
107 }
108109/// It sometimes happens that we want to turn an expectation into
110 /// a **hard constraint** (i.e., something that must be satisfied
111 /// for the program to type-check). `only_has_type` will return
112 /// such a constraint, if it exists.
113pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
114match self {
115ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)),
116NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None,
117 }
118 }
119120/// Like `only_has_type`, but instead of returning `None` if no
121 /// hard constraint exists, creates a fresh type variable.
122pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {
123self.only_has_type(fcx).unwrap_or_else(|| fcx.next_ty_var(span))
124 }
125}