1 use rustc_infer
::infer
::type_variable
::{TypeVariableOrigin, TypeVariableOriginKind}
;
2 use rustc_middle
::ty
::{self, Ty}
;
3 use rustc_span
::{self, Span}
;
5 use super::Expectation
::*;
8 /// When type-checking an expression, we propagate downward
9 /// whatever type hint we are able in the form of an `Expectation`.
10 #[derive(Copy, Clone, Debug)]
11 pub enum Expectation
<'tcx
> {
12 /// We know nothing about what type this expression should have.
15 /// This expression should have the type given (or some subtype).
16 ExpectHasType(Ty
<'tcx
>),
18 /// This expression will be cast to the `Ty`.
19 ExpectCastableToType(Ty
<'tcx
>),
21 /// This rvalue expression will be wrapped in `&` or `Box` and coerced
22 /// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
23 ExpectRvalueLikeUnsized(Ty
<'tcx
>),
28 impl<'a
, 'tcx
> Expectation
<'tcx
> {
29 // Disregard "castable to" expectations because they
30 // can lead us astray. Consider for example `if cond
31 // {22} else {c} as u8` -- if we propagate the
32 // "castable to u8" constraint to 22, it will pick the
33 // type 22u8, which is overly constrained (c might not
34 // be a u8). In effect, the problem is that the
35 // "castable to" expectation is not the tightest thing
36 // we can say, so we want to drop it in this case.
37 // The tightest thing we can say is "must unify with
38 // else branch". Note that in the case of a "has type"
39 // constraint, this limitation does not hold.
41 // If the expected type is just a type variable, then don't use
42 // an expected type. Otherwise, we might write parts of the type
43 // when checking the 'then' block which are incompatible with the
45 pub(super) fn adjust_for_branches(&self, fcx
: &FnCtxt
<'a
, 'tcx
>) -> Expectation
<'tcx
> {
47 ExpectHasType(ety
) => {
48 let ety
= fcx
.shallow_resolve(ety
);
49 if !ety
.is_ty_var() { ExpectHasType(ety) }
else { NoExpectation }
51 ExpectRvalueLikeUnsized(ety
) => ExpectRvalueLikeUnsized(ety
),
56 /// Provides an expectation for an rvalue expression given an *optional*
57 /// hint, which is not required for type safety (the resulting type might
58 /// be checked higher up, as is the case with `&expr` and `box expr`), but
59 /// is useful in determining the concrete type.
61 /// The primary use case is where the expected type is a fat pointer,
62 /// like `&[isize]`. For example, consider the following statement:
64 /// let x: &[isize] = &[1, 2, 3];
66 /// In this case, the expected type for the `&[1, 2, 3]` expression is
67 /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
68 /// expectation `ExpectHasType([isize])`, that would be too strong --
69 /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
70 /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
71 /// to the type `&[isize]`. Therefore, we propagate this more limited hint,
72 /// which still is useful, because it informs integer literals and the like.
73 /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
74 /// for examples of where this comes up,.
75 pub(super) fn rvalue_hint(fcx
: &FnCtxt
<'a
, 'tcx
>, ty
: Ty
<'tcx
>) -> Expectation
<'tcx
> {
76 match fcx
.tcx
.struct_tail_without_normalization(ty
).kind() {
77 ty
::Slice(_
) | ty
::Str
| ty
::Dynamic(..) => ExpectRvalueLikeUnsized(ty
),
78 _
=> ExpectHasType(ty
),
82 // Resolves `expected` by a single level if it is a variable. If
83 // there is no expected type or resolution is not possible (e.g.,
84 // no constraints yet present), just returns `self`.
85 fn resolve(self, fcx
: &FnCtxt
<'a
, 'tcx
>) -> Expectation
<'tcx
> {
87 NoExpectation
=> NoExpectation
,
88 ExpectCastableToType(t
) => ExpectCastableToType(fcx
.resolve_vars_if_possible(t
)),
89 ExpectHasType(t
) => ExpectHasType(fcx
.resolve_vars_if_possible(t
)),
90 ExpectRvalueLikeUnsized(t
) => ExpectRvalueLikeUnsized(fcx
.resolve_vars_if_possible(t
)),
91 IsLast(sp
) => IsLast(sp
),
95 pub(super) fn to_option(self, fcx
: &FnCtxt
<'a
, 'tcx
>) -> Option
<Ty
<'tcx
>> {
96 match self.resolve(fcx
) {
97 NoExpectation
| IsLast(_
) => None
,
98 ExpectCastableToType(ty
) | ExpectHasType(ty
) | ExpectRvalueLikeUnsized(ty
) => Some(ty
),
102 /// It sometimes happens that we want to turn an expectation into
103 /// a **hard constraint** (i.e., something that must be satisfied
104 /// for the program to type-check). `only_has_type` will return
105 /// such a constraint, if it exists.
106 pub(super) fn only_has_type(self, fcx
: &FnCtxt
<'a
, 'tcx
>) -> Option
<Ty
<'tcx
>> {
108 ExpectHasType(ty
) => Some(fcx
.resolve_vars_if_possible(ty
)),
109 NoExpectation
| ExpectCastableToType(_
) | ExpectRvalueLikeUnsized(_
) | IsLast(_
) => {
115 /// Like `only_has_type`, but instead of returning `None` if no
116 /// hard constraint exists, creates a fresh type variable.
117 pub(super) fn coercion_target_type(self, fcx
: &FnCtxt
<'a
, 'tcx
>, span
: Span
) -> Ty
<'tcx
> {
118 self.only_has_type(fcx
).unwrap_or_else(|| {
119 fcx
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }
)