@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
14
14
use rustc_mir_dataflow:: impls:: MaybeStorageLive ;
15
15
use rustc_mir_dataflow:: storage:: AlwaysLiveLocals ;
16
16
use rustc_mir_dataflow:: { Analysis , ResultsCursor } ;
17
- use rustc_target:: abi:: Size ;
17
+ use rustc_target:: abi:: { Size , VariantIdx } ;
18
18
19
19
#[ derive( Copy , Clone , Debug ) ]
20
20
enum EdgeKind {
@@ -244,6 +244,60 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
244
244
self . fail ( location, format ! ( "bad index ({:?} != usize)" , index_ty) )
245
245
}
246
246
}
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
+ }
247
301
self . super_projection_elem ( local, proj_base, elem, context, location) ;
248
302
}
249
303
@@ -291,7 +345,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
291
345
ty:: Array ( ..) | ty:: Slice ( ..)
292
346
) ;
293
347
}
294
- Rvalue :: BinaryOp ( op, vals) | Rvalue :: CheckedBinaryOp ( op , vals ) => {
348
+ Rvalue :: BinaryOp ( op, vals) => {
295
349
use BinOp :: * ;
296
350
let a = vals. 0 . ty ( & self . body . local_decls , self . tcx ) ;
297
351
let b = vals. 1 . ty ( & self . body . local_decls , self . tcx ) ;
@@ -355,17 +409,55 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
355
409
for x in [ a, b] {
356
410
check_kinds ! (
357
411
x,
358
- "Cannot perform op on type {:?}" ,
412
+ "Cannot perform arithmetic on type {:?}" ,
359
413
ty:: Uint ( ..) | ty:: Int ( ..) | ty:: Float ( ..)
360
414
)
361
415
}
362
416
if a != b {
363
417
self . fail (
364
418
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
+ ) ,
366
448
) ;
367
449
}
368
450
}
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) ) ,
369
461
}
370
462
}
371
463
Rvalue :: UnaryOp ( op, operand) => {
0 commit comments