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. adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx>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,. rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx>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`. resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx>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 to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>>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. only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>>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. coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx>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 } 123