@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
1414use rustc_mir_dataflow:: impls:: MaybeStorageLive ;
1515use rustc_mir_dataflow:: storage:: AlwaysLiveLocals ;
1616use rustc_mir_dataflow:: { Analysis , ResultsCursor } ;
17- use rustc_target:: abi:: Size ;
17+ use rustc_target:: abi:: { Size , VariantIdx } ;
1818
1919#[ derive( Copy , Clone , Debug ) ]
2020enum EdgeKind {
@@ -244,6 +244,60 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
244244 self . fail ( location, format ! ( "bad index ({:?} != usize)" , index_ty) )
245245 }
246246 }
247+ if let ProjectionElem :: Field ( f, ty) = elem {
248+ let parent = Place { local, projection : self . tcx . intern_place_elems ( proj_base) } ;
249+ let parent_ty = parent. ty ( & self . body . local_decls , self . tcx ) ;
250+ let fail_out_of_bounds = |this : & Self , location| {
251+ this. fail ( location, format ! ( "Out of bounds field {:?} for {:?}" , f, parent_ty) ) ;
252+ } ;
253+ let check_equal = |this : & Self , location, f_ty| {
254+ if !this. mir_assign_valid_types ( ty, f_ty) {
255+ this. fail (
256+ location,
257+ format ! (
258+ "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is {:?}" ,
259+ parent, f, ty, f_ty
260+ )
261+ )
262+ }
263+ } ;
264+ match parent_ty. ty . kind ( ) {
265+ ty:: Tuple ( fields) => {
266+ let Some ( f_ty) = fields. get ( f. as_usize ( ) ) else {
267+ fail_out_of_bounds ( self , location) ;
268+ return ;
269+ } ;
270+ check_equal ( self , location, * f_ty) ;
271+ }
272+ ty:: Adt ( adt_def, substs) => {
273+ let var = parent_ty. variant_index . unwrap_or ( VariantIdx :: from_u32 ( 0 ) ) ;
274+ let Some ( field) = adt_def. variant ( var) . fields . get ( f. as_usize ( ) ) else {
275+ fail_out_of_bounds ( self , location) ;
276+ return ;
277+ } ;
278+ check_equal ( self , location, field. ty ( self . tcx , substs) ) ;
279+ }
280+ ty:: Closure ( _, substs) => {
281+ let substs = substs. as_closure ( ) ;
282+ let Some ( f_ty) = substs. upvar_tys ( ) . nth ( f. as_usize ( ) ) else {
283+ fail_out_of_bounds ( self , location) ;
284+ return ;
285+ } ;
286+ check_equal ( self , location, f_ty) ;
287+ }
288+ ty:: Generator ( _, substs, _) => {
289+ let substs = substs. as_generator ( ) ;
290+ let Some ( f_ty) = substs. upvar_tys ( ) . nth ( f. as_usize ( ) ) else {
291+ fail_out_of_bounds ( self , location) ;
292+ return ;
293+ } ;
294+ check_equal ( self , location, f_ty) ;
295+ }
296+ _ => {
297+ self . fail ( location, format ! ( "{:?} does not have fields" , parent_ty. ty) ) ;
298+ }
299+ }
300+ }
247301 self . super_projection_elem ( local, proj_base, elem, context, location) ;
248302 }
249303
@@ -291,7 +345,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
291345 ty:: Array ( ..) | ty:: Slice ( ..)
292346 ) ;
293347 }
294- Rvalue :: BinaryOp ( op, vals) | Rvalue :: CheckedBinaryOp ( op , vals ) => {
348+ Rvalue :: BinaryOp ( op, vals) => {
295349 use BinOp :: * ;
296350 let a = vals. 0 . ty ( & self . body . local_decls , self . tcx ) ;
297351 let b = vals. 1 . ty ( & self . body . local_decls , self . tcx ) ;
@@ -355,17 +409,55 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
355409 for x in [ a, b] {
356410 check_kinds ! (
357411 x,
358- "Cannot perform op on type {:?}" ,
412+ "Cannot perform arithmetic on type {:?}" ,
359413 ty:: Uint ( ..) | ty:: Int ( ..) | ty:: Float ( ..)
360414 )
361415 }
362416 if a != b {
363417 self . fail (
364418 location,
365- format ! ( "Cannot perform op on unequal types {:?} and {:?}" , a, b) ,
419+ format ! (
420+ "Cannot perform arithmetic on unequal types {:?} and {:?}" ,
421+ a, b
422+ ) ,
423+ ) ;
424+ }
425+ }
426+ }
427+ }
428+ Rvalue :: CheckedBinaryOp ( op, vals) => {
429+ use BinOp :: * ;
430+ let a = vals. 0 . ty ( & self . body . local_decls , self . tcx ) ;
431+ let b = vals. 1 . ty ( & self . body . local_decls , self . tcx ) ;
432+ match op {
433+ Add | Sub | Mul => {
434+ for x in [ a, b] {
435+ check_kinds ! (
436+ x,
437+ "Cannot perform checked arithmetic on type {:?}" ,
438+ ty:: Uint ( ..) | ty:: Int ( ..)
439+ )
440+ }
441+ if a != b {
442+ self . fail (
443+ location,
444+ format ! (
445+ "Cannot perform checked arithmetic on unequal types {:?} and {:?}" ,
446+ a, b
447+ ) ,
366448 ) ;
367449 }
368450 }
451+ Shl | Shr => {
452+ for x in [ a, b] {
453+ check_kinds ! (
454+ x,
455+ "Cannot perform checked shift on non-integer type {:?}" ,
456+ ty:: Uint ( ..) | ty:: Int ( ..)
457+ )
458+ }
459+ }
460+ _ => self . fail ( location, format ! ( "There is no checked version of {:?}" , op) ) ,
369461 }
370462 }
371463 Rvalue :: UnaryOp ( op, operand) => {
0 commit comments