@@ -34,12 +34,16 @@ use rustc_hir::intravisit::Visitor;
34
34
use rustc_hir:: { ExprKind , QPath } ;
35
35
use rustc_infer:: infer;
36
36
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
37
+ use rustc_infer:: infer:: InferOk ;
37
38
use rustc_middle:: ty;
38
39
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AllowTwoPhase } ;
40
+ use rustc_middle:: ty:: error:: TypeError :: { FieldMisMatch , Sorts } ;
41
+ use rustc_middle:: ty:: relate:: expected_found_bool;
39
42
use rustc_middle:: ty:: subst:: SubstsRef ;
40
43
use rustc_middle:: ty:: Ty ;
41
44
use rustc_middle:: ty:: TypeFoldable ;
42
45
use rustc_middle:: ty:: { AdtKind , Visibility } ;
46
+ use rustc_session:: parse:: feature_err;
43
47
use rustc_span:: edition:: LATEST_STABLE_EDITION ;
44
48
use rustc_span:: hygiene:: DesugaringKind ;
45
49
use rustc_span:: lev_distance:: find_best_match_for_name;
@@ -1283,49 +1287,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1283
1287
. emit_err ( StructExprNonExhaustive { span : expr. span , what : adt. variant_descr ( ) } ) ;
1284
1288
}
1285
1289
1286
- let error_happened = self . check_expr_struct_fields (
1290
+ self . check_expr_struct_fields (
1287
1291
adt_ty,
1288
1292
expected,
1289
1293
expr. hir_id ,
1290
1294
qpath. span ( ) ,
1291
1295
variant,
1292
1296
fields,
1293
- base_expr. is_none ( ) ,
1297
+ base_expr,
1294
1298
expr. span ,
1295
1299
) ;
1296
- if let Some ( base_expr) = base_expr {
1297
- // If check_expr_struct_fields hit an error, do not attempt to populate
1298
- // the fields with the base_expr. This could cause us to hit errors later
1299
- // when certain fields are assumed to exist that in fact do not.
1300
- if !error_happened {
1301
- self . check_expr_has_type_or_error ( base_expr, adt_ty, |_| { } ) ;
1302
- match adt_ty. kind ( ) {
1303
- ty:: Adt ( adt, substs) if adt. is_struct ( ) => {
1304
- let fru_field_types = adt
1305
- . non_enum_variant ( )
1306
- . fields
1307
- . iter ( )
1308
- . map ( |f| {
1309
- self . normalize_associated_types_in (
1310
- expr. span ,
1311
- f. ty ( self . tcx , substs) ,
1312
- )
1313
- } )
1314
- . collect ( ) ;
1315
-
1316
- self . typeck_results
1317
- . borrow_mut ( )
1318
- . fru_field_types_mut ( )
1319
- . insert ( expr. hir_id , fru_field_types) ;
1320
- }
1321
- _ => {
1322
- self . tcx
1323
- . sess
1324
- . emit_err ( FunctionalRecordUpdateOnNonStruct { span : base_expr. span } ) ;
1325
- }
1326
- }
1327
- }
1328
- }
1300
+
1329
1301
self . require_type_is_sized ( adt_ty, expr. span , traits:: StructInitializerSized ) ;
1330
1302
adt_ty
1331
1303
}
@@ -1338,9 +1310,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1338
1310
span : Span ,
1339
1311
variant : & ' tcx ty:: VariantDef ,
1340
1312
ast_fields : & ' tcx [ hir:: ExprField < ' tcx > ] ,
1341
- check_completeness : bool ,
1313
+ base_expr : & ' tcx Option < & ' tcx hir :: Expr < ' tcx > > ,
1342
1314
expr_span : Span ,
1343
- ) -> bool {
1315
+ ) {
1344
1316
let tcx = self . tcx ;
1345
1317
1346
1318
let adt_ty_hint = self
@@ -1415,7 +1387,116 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1415
1387
)
1416
1388
. emit ( ) ;
1417
1389
}
1418
- } else if check_completeness && !error_happened && !remaining_fields. is_empty ( ) {
1390
+ }
1391
+
1392
+ // If check_expr_struct_fields hit an error, do not attempt to populate
1393
+ // the fields with the base_expr. This could cause us to hit errors later
1394
+ // when certain fields are assumed to exist that in fact do not.
1395
+ if error_happened {
1396
+ return ;
1397
+ }
1398
+
1399
+ if let Some ( base_expr) = base_expr {
1400
+ // FIXME: We are currently creating two branches here in order to maintain
1401
+ // consistency. But they should be merged as much as possible.
1402
+ let fru_tys = if self . tcx . features ( ) . type_changing_struct_update {
1403
+ let base_ty = self . check_expr ( base_expr) ;
1404
+ match adt_ty. kind ( ) {
1405
+ ty:: Adt ( adt, substs) if adt. is_struct ( ) => {
1406
+ match base_ty. kind ( ) {
1407
+ ty:: Adt ( base_adt, base_subs) if adt == base_adt => {
1408
+ variant
1409
+ . fields
1410
+ . iter ( )
1411
+ . map ( |f| {
1412
+ let fru_ty = self . normalize_associated_types_in (
1413
+ expr_span,
1414
+ self . field_ty ( base_expr. span , f, base_subs) ,
1415
+ ) ;
1416
+ let ident = self . tcx . adjust_ident ( f. ident , variant. def_id ) ;
1417
+ if let Some ( _) = remaining_fields. remove ( & ident) {
1418
+ let target_ty =
1419
+ self . field_ty ( base_expr. span , f, substs) ;
1420
+ let cause = self . misc ( base_expr. span ) ;
1421
+ match self
1422
+ . at ( & cause, self . param_env )
1423
+ . sup ( target_ty, fru_ty)
1424
+ {
1425
+ Ok ( InferOk { obligations, value : ( ) } ) => {
1426
+ self . register_predicates ( obligations)
1427
+ }
1428
+ // FIXME: Need better diagnostics for `FieldMisMatch` error
1429
+ Err ( _) => self
1430
+ . report_mismatched_types (
1431
+ & cause,
1432
+ target_ty,
1433
+ fru_ty,
1434
+ FieldMisMatch (
1435
+ variant. ident . name ,
1436
+ ident. name ,
1437
+ ) ,
1438
+ )
1439
+ . emit ( ) ,
1440
+ }
1441
+ }
1442
+ fru_ty
1443
+ } )
1444
+ . collect ( )
1445
+ }
1446
+ _ => {
1447
+ return self
1448
+ . report_mismatched_types (
1449
+ & self . misc ( base_expr. span ) ,
1450
+ adt_ty,
1451
+ base_ty,
1452
+ Sorts ( expected_found_bool ( true , adt_ty, base_ty) ) ,
1453
+ )
1454
+ . emit ( ) ;
1455
+ }
1456
+ }
1457
+ }
1458
+ _ => {
1459
+ return self
1460
+ . tcx
1461
+ . sess
1462
+ . emit_err ( FunctionalRecordUpdateOnNonStruct { span : base_expr. span } ) ;
1463
+ }
1464
+ }
1465
+ } else {
1466
+ self . check_expr_has_type_or_error ( base_expr, adt_ty, |_| {
1467
+ let base_ty = self . check_expr ( base_expr) ;
1468
+ let same_adt = match ( adt_ty. kind ( ) , base_ty. kind ( ) ) {
1469
+ ( ty:: Adt ( adt, _) , ty:: Adt ( base_adt, _) ) if adt == base_adt => true ,
1470
+ _ => false ,
1471
+ } ;
1472
+ if self . tcx . sess . is_nightly_build ( ) && same_adt {
1473
+ feature_err (
1474
+ & self . tcx . sess . parse_sess ,
1475
+ sym:: type_changing_struct_update,
1476
+ base_expr. span ,
1477
+ "type changing struct updating is experimental" ,
1478
+ )
1479
+ . emit ( ) ;
1480
+ }
1481
+ } ) ;
1482
+ match adt_ty. kind ( ) {
1483
+ ty:: Adt ( adt, substs) if adt. is_struct ( ) => variant
1484
+ . fields
1485
+ . iter ( )
1486
+ . map ( |f| {
1487
+ self . normalize_associated_types_in ( expr_span, f. ty ( self . tcx , substs) )
1488
+ } )
1489
+ . collect ( ) ,
1490
+ _ => {
1491
+ return self
1492
+ . tcx
1493
+ . sess
1494
+ . emit_err ( FunctionalRecordUpdateOnNonStruct { span : base_expr. span } ) ;
1495
+ }
1496
+ }
1497
+ } ;
1498
+ self . typeck_results . borrow_mut ( ) . fru_field_types_mut ( ) . insert ( expr_id, fru_tys) ;
1499
+ } else if kind_name != "union" && !remaining_fields. is_empty ( ) {
1419
1500
let inaccessible_remaining_fields = remaining_fields. iter ( ) . any ( |( _, ( _, field) ) | {
1420
1501
!field. vis . is_accessible_from ( tcx. parent_module ( expr_id) . to_def_id ( ) , tcx)
1421
1502
} ) ;
@@ -1426,8 +1507,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1426
1507
self . report_missing_fields ( adt_ty, span, remaining_fields) ;
1427
1508
}
1428
1509
}
1429
-
1430
- error_happened
1431
1510
}
1432
1511
1433
1512
fn check_struct_fields_on_error (
0 commit comments