@@ -1060,6 +1060,164 @@ fn compare_impl_method(tcx: &ty::ctxt,
10601060 }
10611061}
10621062
1063+ fn check_cast ( fcx : & FnCtxt ,
1064+ e : & ast:: Expr ,
1065+ t : & ast:: Ty ,
1066+ id : ast:: NodeId ,
1067+ span : Span ) {
1068+ // Find the type of `e`. Supply hints based on the type we are casting to,
1069+ // if appropriate.
1070+ let t_1 = fcx. to_ty ( t) ;
1071+ let t_1 = structurally_resolved_type ( fcx, span, t_1) ;
1072+
1073+ if ty:: type_is_scalar ( t_1) {
1074+ // Supply the type as a hint so as to influence integer
1075+ // literals and other things that might care.
1076+ check_expr_with_hint ( fcx, e, t_1)
1077+ } else {
1078+ check_expr ( fcx, e)
1079+ }
1080+
1081+ let t_e = fcx. expr_ty ( e) ;
1082+
1083+ debug ! ( "t_1={}" , fcx. infcx( ) . ty_to_str( t_1) ) ;
1084+ debug ! ( "t_e={}" , fcx. infcx( ) . ty_to_str( t_e) ) ;
1085+
1086+ if ty:: type_is_error ( t_e) {
1087+ fcx. write_error ( id) ;
1088+ return
1089+ }
1090+ if ty:: type_is_bot ( t_e) {
1091+ fcx. write_bot ( id) ;
1092+ return
1093+ }
1094+
1095+ if ty:: type_is_trait ( t_1) {
1096+ // This will be looked up later on.
1097+ fcx. write_ty ( id, t_1) ;
1098+ return
1099+ }
1100+
1101+ let t_1 = structurally_resolved_type ( fcx, span, t_1) ;
1102+ let t_e = structurally_resolved_type ( fcx, span, t_e) ;
1103+
1104+ if ty:: type_is_nil ( t_e) {
1105+ fcx. type_error_message ( span, |actual| {
1106+ format ! ( "cast from nil: `{}` as `{}`" ,
1107+ actual,
1108+ fcx. infcx( ) . ty_to_str( t_1) )
1109+ } , t_e, None ) ;
1110+ } else if ty:: type_is_nil ( t_1) {
1111+ fcx. type_error_message ( span, |actual| {
1112+ format ! ( "cast to nil: `{}` as `{}`" ,
1113+ actual,
1114+ fcx. infcx( ) . ty_to_str( t_1) )
1115+ } , t_e, None ) ;
1116+ }
1117+
1118+ let t_1_is_scalar = ty:: type_is_scalar ( t_1) ;
1119+ let t_1_is_char = ty:: type_is_char ( t_1) ;
1120+ let t_1_is_bare_fn = ty:: type_is_bare_fn ( t_1) ;
1121+ let t_1_is_float = ty:: type_is_floating_point ( t_1) ;
1122+
1123+ // casts to scalars other than `char` and `bare fn` are trivial
1124+ let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
1125+ if ty:: type_is_c_like_enum ( fcx. tcx ( ) , t_e) && t_1_is_trivial {
1126+ if t_1_is_float {
1127+ fcx. type_error_message ( span, |actual| {
1128+ format ! ( "illegal cast; cast through an \
1129+ integer first: `{}` as `{}`",
1130+ actual,
1131+ fcx. infcx( ) . ty_to_str( t_1) )
1132+ } , t_e, None ) ;
1133+ }
1134+ // casts from C-like enums are allowed
1135+ } else if t_1_is_char {
1136+ let t_e = fcx. infcx ( ) . resolve_type_vars_if_possible ( t_e) ;
1137+ if ty:: get ( t_e) . sty != ty:: ty_uint ( ast:: TyU8 ) {
1138+ fcx. type_error_message ( span, |actual| {
1139+ format ! ( "only `u8` can be cast as \
1140+ `char`, not `{}`", actual)
1141+ } , t_e, None ) ;
1142+ }
1143+ } else if ty:: get ( t_1) . sty == ty:: ty_bool {
1144+ fcx. tcx ( )
1145+ . sess
1146+ . span_err ( span,
1147+ "cannot cast as `bool`, compare with zero instead" ) ;
1148+ } else if ty:: type_is_region_ptr ( t_e) && ty:: type_is_unsafe_ptr ( t_1) {
1149+ fn is_vec ( t : ty:: t ) -> bool {
1150+ match ty:: get ( t) . sty {
1151+ ty:: ty_vec( ..) => true ,
1152+ ty:: ty_ptr( ty:: mt { ty : t, ..} ) |
1153+ ty:: ty_rptr( _, ty:: mt { ty : t, ..} ) |
1154+ ty:: ty_box( t) |
1155+ ty:: ty_uniq( t) => {
1156+ match ty:: get ( t) . sty {
1157+ ty:: ty_vec( _, None ) => true ,
1158+ _ => false ,
1159+ }
1160+ }
1161+ _ => false
1162+ }
1163+ }
1164+ fn types_compatible ( fcx : & FnCtxt , sp : Span ,
1165+ t1 : ty:: t , t2 : ty:: t ) -> bool {
1166+ if !is_vec ( t1) {
1167+ // If the type being casted from is not a vector, this special
1168+ // case does not apply.
1169+ return false
1170+ }
1171+ if ty:: type_needs_infer ( t2) {
1172+ // This prevents this special case from going off when casting
1173+ // to a type that isn't fully specified; e.g. `as *_`. (Issue
1174+ // #14893.)
1175+ return false
1176+ }
1177+
1178+ let el = ty:: sequence_element_type ( fcx. tcx ( ) , t1) ;
1179+ infer:: mk_eqty ( fcx. infcx ( ) ,
1180+ false ,
1181+ infer:: Misc ( sp) ,
1182+ el,
1183+ t2) . is_ok ( )
1184+ }
1185+
1186+ // Due to the limitations of LLVM global constants,
1187+ // region pointers end up pointing at copies of
1188+ // vector elements instead of the original values.
1189+ // To allow unsafe pointers to work correctly, we
1190+ // need to special-case obtaining an unsafe pointer
1191+ // from a region pointer to a vector.
1192+
1193+ /* this cast is only allowed from &[T] to *T or
1194+ &T to *T. */
1195+ match ( & ty:: get ( t_e) . sty , & ty:: get ( t_1) . sty ) {
1196+ ( & ty:: ty_rptr( _, ty:: mt { ty : mt1, mutbl : ast:: MutImmutable } ) ,
1197+ & ty:: ty_ptr( ty:: mt { ty : mt2, mutbl : ast:: MutImmutable } ) )
1198+ if types_compatible ( fcx, e. span , mt1, mt2) => {
1199+ /* this case is allowed */
1200+ }
1201+ _ => {
1202+ demand:: coerce ( fcx, e. span , t_1, & * e) ;
1203+ }
1204+ }
1205+ } else if !( ty:: type_is_scalar ( t_e) && t_1_is_trivial) {
1206+ /*
1207+ If more type combinations should be supported than are
1208+ supported here, then file an enhancement issue and
1209+ record the issue number in this comment.
1210+ */
1211+ fcx. type_error_message ( span, |actual| {
1212+ format ! ( "non-scalar cast: `{}` as `{}`" ,
1213+ actual,
1214+ fcx. infcx( ) . ty_to_str( t_1) )
1215+ } , t_e, None ) ;
1216+ }
1217+
1218+ fcx. write_ty ( id, t_1) ;
1219+ }
1220+
10631221impl < ' a > AstConv for FnCtxt < ' a > {
10641222 fn tcx < ' a > ( & ' a self ) -> & ' a ty:: ctxt { self . ccx . tcx }
10651223
@@ -3049,11 +3207,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
30493207 fcx. write_bot ( id) ;
30503208 }
30513209 }
3052- ast:: ExprCast ( expr_from, t) => {
3053- let ty_to = fcx. to_ty ( t) ;
3054- debug ! ( "ExprCast ty_to={}" , fcx. infcx( ) . ty_to_str( ty_to) ) ;
3055- check_cast ( fcx, expr_from, ty_to) ;
3056- fcx. write_ty ( id, ty_to) ;
3210+ ast:: ExprCast ( ref e, ref t) => {
3211+ check_cast ( fcx, & * * e, & * * t, id, expr. span ) ;
30573212 }
30583213 ast:: ExprVec ( ref args) => {
30593214 let t: ty:: t = fcx. infcx ( ) . next_ty_var ( ) ;
@@ -3248,130 +3403,6 @@ impl Repr for Expectation {
32483403 }
32493404}
32503405
3251- fn check_cast ( fcx : & FnCtxt , expr_from : Gc < ast:: Expr > , ty_to : ty:: t ) {
3252- // Find the type of `expr_from`. Supply hints based on the type
3253- // we are casting to, if appropriate.
3254- let ty_to = structurally_resolved_type ( fcx, expr_from. span , ty_to) ;
3255- if ty:: type_is_scalar ( ty_to) {
3256- // Supply the type as a hint so as to influence integer
3257- // literals and other things that might care.
3258- check_expr_with_hint ( fcx, expr_from, ty_to)
3259- } else {
3260- check_expr ( fcx, expr_from)
3261- }
3262- let ty_from = fcx. expr_ty ( expr_from) ;
3263-
3264- // Object creation is checked during the vtable phase.
3265- if ty:: type_is_trait ( ty_to) {
3266- check_expr ( fcx, expr_from) ;
3267- return ;
3268- }
3269-
3270- let ty_from = fcx. infcx ( ) . resolve_type_vars_if_possible ( ty_from) ;
3271-
3272- if ty:: type_is_nil ( ty_from) {
3273- fcx. type_error_message ( expr_from. span , |actual| {
3274- format ! ( "cast from nil: `{}` as `{}`" , actual,
3275- fcx. infcx( ) . ty_to_str( ty_to) )
3276- } , ty_from, None ) ;
3277- return ;
3278- }
3279-
3280- if ty:: type_is_nil ( ty_to) {
3281- fcx. type_error_message ( expr_from. span , |actual| {
3282- format ! ( "cast to nil: `{}` as `{}`" , actual,
3283- fcx. infcx( ) . ty_to_str( ty_to) )
3284- } , ty_from, None ) ;
3285- return ;
3286- }
3287-
3288- let t_e = structurally_resolved_type ( fcx, expr_from. span , ty_from) ;
3289- let t_1 = structurally_resolved_type ( fcx, expr_from. span , ty_to) ;
3290-
3291- let to_is_scalar = ty:: type_is_scalar ( t_1) ;
3292- let to_is_float = ty:: type_is_floating_point ( t_1) ;
3293- let to_is_char = ty:: type_is_char ( t_1) ;
3294- let to_is_bare_fn = ty:: type_is_bare_fn ( t_1) ;
3295-
3296- // casts to scalars other than `char` and `bare fn` are trivial
3297- let to_is_trivial = to_is_scalar &&
3298- !to_is_char && !to_is_bare_fn;
3299-
3300- if ty:: type_is_c_like_enum ( fcx. tcx ( ) , t_e) && to_is_trivial {
3301- if to_is_float {
3302- fcx. type_error_message ( expr_from. span , |actual| {
3303- format ! ( "illegal cast; cast through an integer first: `{}` \
3304- as `{}`",
3305- actual,
3306- fcx. infcx( ) . ty_to_str( t_1) )
3307- } , ty_from, None ) ;
3308- }
3309- // casts from C-like enums are allowed
3310- } else if to_is_char {
3311- if ty:: get ( ty_from) . sty != ty:: ty_uint ( ast:: TyU8 ) {
3312- fcx. type_error_message ( expr_from. span , |actual| {
3313- format ! ( "only `u8` can be cast as `char`, not `{}`" , actual)
3314- } , ty_from, None ) ;
3315- }
3316- } else if ty:: type_is_bool ( t_1) {
3317- fcx. tcx ( ) . sess . span_err ( expr_from. span ,
3318- "cannot cast as `bool`, compare with zero instead" ) ;
3319- } else if ty:: type_is_region_ptr ( t_e) && ty:: type_is_unsafe_ptr ( t_1) {
3320- fn is_vec ( t : ty:: t ) -> bool {
3321- match ty:: get ( t) . sty {
3322- ty:: ty_vec( ..) => true ,
3323- ty:: ty_ptr( ty:: mt { ty : t, ..} ) |
3324- ty:: ty_rptr( _, ty:: mt { ty : t, ..} ) |
3325- ty:: ty_box( t) |
3326- ty:: ty_uniq( t) => match ty:: get ( t) . sty {
3327- ty:: ty_vec( _, None ) => true ,
3328- _ => false ,
3329- } ,
3330- _ => false
3331- }
3332- }
3333- fn types_compatible ( fcx : & FnCtxt , sp : Span ,
3334- t1 : ty:: t , t2 : ty:: t ) -> bool {
3335- if !is_vec ( t1) {
3336- false
3337- } else {
3338- let el = ty:: sequence_element_type ( fcx. tcx ( ) ,
3339- t1) ;
3340- infer:: mk_eqty ( fcx. infcx ( ) , false ,
3341- infer:: Misc ( sp) , el, t2) . is_ok ( )
3342- }
3343- }
3344-
3345- // Due to the limitations of LLVM global constants,
3346- // region pointers end up pointing at copies of
3347- // vector elements instead of the original values.
3348- // To allow unsafe pointers to work correctly, we
3349- // need to special-case obtaining an unsafe pointer
3350- // from a region pointer to a vector.
3351-
3352- /* this cast is only allowed from &[T] to *T or
3353- &T to *T. */
3354- match ( & ty:: get ( t_e) . sty , & ty:: get ( t_1) . sty ) {
3355- ( & ty:: ty_rptr( _, ty:: mt { ty : mt1, mutbl : ast:: MutImmutable } ) ,
3356- & ty:: ty_ptr( ty:: mt { ty : mt2, mutbl : ast:: MutImmutable } ) )
3357- if types_compatible ( fcx, expr_from. span , mt1, mt2) => {
3358- /* this case is allowed */
3359- }
3360- _ => {
3361- demand:: coerce ( fcx, expr_from. span , ty_to, expr_from) ;
3362- }
3363- }
3364- } else if !( ty:: type_is_scalar ( t_e) && to_is_trivial) {
3365- // If more type combinations should be supported than are
3366- // supported here, then file an enhancement issue and
3367- // record the issue number in this comment.
3368- fcx. type_error_message ( expr_from. span , |actual| {
3369- format ! ( "non-scalar cast: `{}` as `{}`" , actual,
3370- fcx. infcx( ) . ty_to_str( ty_to) )
3371- } , ty_from, None ) ;
3372- }
3373- }
3374-
33753406pub fn require_uint ( fcx : & FnCtxt , sp : Span , t : ty:: t ) {
33763407 if !type_is_uint ( fcx, sp, t) {
33773408 fcx. type_error_message ( sp, |actual| {
0 commit comments