@@ -176,6 +176,10 @@ enum Expectation<'tcx> {
176176
177177 /// This expression will be cast to the `Ty`
178178 ExpectCastableToType ( Ty < ' tcx > ) ,
179+
180+ /// This rvalue expression will be wrapped in `&` or `Box` and coerced
181+ /// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
182+ ExpectRvalueLikeUnsized ( Ty < ' tcx > ) ,
179183}
180184
181185impl < ' tcx > Expectation < ' tcx > {
@@ -196,7 +200,7 @@ impl<'tcx> Expectation<'tcx> {
196200 // when checking the 'then' block which are incompatible with the
197201 // 'else' branch.
198202 fn adjust_for_branches < ' a > ( & self , fcx : & FnCtxt < ' a , ' tcx > ) -> Expectation < ' tcx > {
199- match self . only_has_type ( ) {
203+ match * self {
200204 ExpectHasType ( ety) => {
201205 let ety = fcx. infcx ( ) . shallow_resolve ( ety) ;
202206 if !ty:: type_is_ty_var ( ety) {
@@ -205,6 +209,9 @@ impl<'tcx> Expectation<'tcx> {
205209 NoExpectation
206210 }
207211 }
212+ ExpectRvalueLikeUnsized ( ety) => {
213+ ExpectRvalueLikeUnsized ( ety)
214+ }
208215 _ => NoExpectation
209216 }
210217 }
@@ -3678,7 +3685,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
36783685 match unop {
36793686 ast:: UnUniq => match ty. sty {
36803687 ty:: ty_uniq( ty) => {
3681- ExpectHasType ( ty)
3688+ Expectation :: rvalue_hint ( ty)
36823689 }
36833690 _ => {
36843691 NoExpectation
@@ -3767,7 +3774,16 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
37673774 let expected = expected. only_has_type ( ) ;
37683775 let hint = expected. map ( fcx, |ty| {
37693776 match ty. sty {
3770- ty:: ty_rptr( _, ref mt) | ty:: ty_ptr( ref mt) => ExpectHasType ( mt. ty ) ,
3777+ ty:: ty_rptr( _, ref mt) | ty:: ty_ptr( ref mt) => {
3778+ if ty:: expr_is_lval ( fcx. tcx ( ) , & * * oprnd) {
3779+ // Lvalues may legitimately have unsized types.
3780+ // For example, dereferences of a fat pointer and
3781+ // the last field of a struct can be unsized.
3782+ ExpectHasType ( mt. ty )
3783+ } else {
3784+ Expectation :: rvalue_hint ( mt. ty )
3785+ }
3786+ }
37713787 _ => NoExpectation
37723788 }
37733789 } ) ;
@@ -3985,15 +4001,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
39854001 check_cast ( fcx, expr, & * * e, & * * t) ;
39864002 }
39874003 ast:: ExprVec ( ref args) => {
3988- let uty = match expected {
3989- ExpectHasType ( uty) => {
3990- match uty. sty {
3991- ty:: ty_vec( ty, _) => Some ( ty) ,
3992- _ => None
3993- }
4004+ let uty = expected. map_to_option ( fcx, |uty| {
4005+ match uty. sty {
4006+ ty:: ty_vec( ty, _) => Some ( ty) ,
4007+ _ => None
39944008 }
3995- _ => None
3996- } ;
4009+ } ) ;
39974010
39984011 let typ = match uty {
39994012 Some ( uty) => {
@@ -4020,8 +4033,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
40204033 let uty = match expected {
40214034 ExpectHasType ( uty) => {
40224035 match uty. sty {
4023- ty:: ty_vec( ty, _) => Some ( ty) ,
4024- _ => None
4036+ ty:: ty_vec( ty, _) => Some ( ty) ,
4037+ _ => None
40254038 }
40264039 }
40274040 _ => None
@@ -4298,10 +4311,38 @@ fn constrain_path_type_parameters(fcx: &FnCtxt,
42984311}
42994312
43004313impl < ' tcx > Expectation < ' tcx > {
4314+ /// Provide an expectation for an rvalue expression given an *optional*
4315+ /// hint, which is not required for type safety (the resulting type might
4316+ /// be checked higher up, as is the case with `&expr` and `box expr`), but
4317+ /// is useful in determining the concrete type.
4318+ ///
4319+ /// The primary use case is where the expected type is a fat pointer,
4320+ /// like `&[int]`. For example, consider the following statement:
4321+ ///
4322+ /// let x: &[int] = &[1, 2, 3];
4323+ ///
4324+ /// In this case, the expected type for the `&[1, 2, 3]` expression is
4325+ /// `&[int]`. If however we were to say that `[1, 2, 3]` has the
4326+ /// expectation `ExpectHasType([int])`, that would be too strong --
4327+ /// `[1, 2, 3]` does not have the type `[int]` but rather `[int, ..3]`.
4328+ /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
4329+ /// to the type `&[int]`. Therefore, we propagate this more limited hint,
4330+ /// which still is useful, because it informs integer literals and the like.
4331+ /// See the test case `test/run-pass/coerce-expect-unsized.rs` and #20169
4332+ /// for examples of where this comes up,.
4333+ fn rvalue_hint ( ty : Ty < ' tcx > ) -> Expectation < ' tcx > {
4334+ match ty. sty {
4335+ ty:: ty_vec( _, None ) | ty:: ty_trait( ..) => {
4336+ ExpectRvalueLikeUnsized ( ty)
4337+ }
4338+ _ => ExpectHasType ( ty)
4339+ }
4340+ }
4341+
43014342 fn only_has_type ( self ) -> Expectation < ' tcx > {
43024343 match self {
4303- NoExpectation | ExpectCastableToType ( .. ) => NoExpectation ,
4304- ExpectHasType ( t ) => ExpectHasType ( t )
4344+ ExpectHasType ( t ) => ExpectHasType ( t ) ,
4345+ _ => NoExpectation
43054346 }
43064347 }
43074348
@@ -4321,6 +4362,10 @@ impl<'tcx> Expectation<'tcx> {
43214362 ExpectHasType (
43224363 fcx. infcx ( ) . resolve_type_vars_if_possible ( & t) )
43234364 }
4365+ ExpectRvalueLikeUnsized ( t) => {
4366+ ExpectRvalueLikeUnsized (
4367+ fcx. infcx ( ) . resolve_type_vars_if_possible ( & t) )
4368+ }
43244369 }
43254370 }
43264371
@@ -4329,7 +4374,9 @@ impl<'tcx> Expectation<'tcx> {
43294374 {
43304375 match self . resolve ( fcx) {
43314376 NoExpectation => NoExpectation ,
4332- ExpectCastableToType ( ty) | ExpectHasType ( ty) => unpack ( ty) ,
4377+ ExpectCastableToType ( ty) |
4378+ ExpectHasType ( ty) |
4379+ ExpectRvalueLikeUnsized ( ty) => unpack ( ty) ,
43334380 }
43344381 }
43354382
@@ -4338,7 +4385,9 @@ impl<'tcx> Expectation<'tcx> {
43384385 {
43394386 match self . resolve ( fcx) {
43404387 NoExpectation => None ,
4341- ExpectCastableToType ( ty) | ExpectHasType ( ty) => unpack ( ty) ,
4388+ ExpectCastableToType ( ty) |
4389+ ExpectHasType ( ty) |
4390+ ExpectRvalueLikeUnsized ( ty) => unpack ( ty) ,
43424391 }
43434392 }
43444393}
@@ -4351,6 +4400,8 @@ impl<'tcx> Repr<'tcx> for Expectation<'tcx> {
43514400 t. repr( tcx) ) ,
43524401 ExpectCastableToType ( t) => format ! ( "ExpectCastableToType({})" ,
43534402 t. repr( tcx) ) ,
4403+ ExpectRvalueLikeUnsized ( t) => format ! ( "ExpectRvalueLikeUnsized({})" ,
4404+ t. repr( tcx) ) ,
43544405 }
43554406 }
43564407}
0 commit comments