]>
Commit | Line | Data |
---|---|---|
1 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; | |
2 | use rustc_middle::ty::{self, Ty}; | |
3 | use rustc_span::{self, Span}; | |
4 | ||
5 | use super::Expectation::*; | |
6 | use super::FnCtxt; | |
7 | ||
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. | |
13 | NoExpectation, | |
14 | ||
15 | /// This expression should have the type given (or some subtype). | |
16 | ExpectHasType(Ty<'tcx>), | |
17 | ||
18 | /// This expression will be cast to the `Ty`. | |
19 | ExpectCastableToType(Ty<'tcx>), | |
20 | ||
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>), | |
24 | ||
25 | IsLast(Span), | |
26 | } | |
27 | ||
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. | |
40 | ||
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 | |
44 | // 'else' branch. | |
45 | pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { | |
46 | match *self { | |
47 | ExpectHasType(ety) => { | |
48 | let ety = fcx.shallow_resolve(ety); | |
49 | if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } | |
50 | } | |
51 | ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety), | |
52 | _ => NoExpectation, | |
53 | } | |
54 | } | |
55 | ||
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. | |
60 | /// | |
61 | /// The primary use case is where the expected type is a fat pointer, | |
62 | /// like `&[isize]`. For example, consider the following statement: | |
63 | /// | |
64 | /// let x: &[isize] = &[1, 2, 3]; | |
65 | /// | |
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), | |
79 | } | |
80 | } | |
81 | ||
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> { | |
86 | match self { | |
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), | |
92 | } | |
93 | } | |
94 | ||
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), | |
99 | } | |
100 | } | |
101 | ||
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>> { | |
107 | match self { | |
108 | ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)), | |
109 | NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => { | |
110 | None | |
111 | } | |
112 | } | |
113 | } | |
114 | ||
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 }) | |
120 | }) | |
121 | } | |
122 | } |