@@ -23,7 +23,7 @@ use crate::type_error_struct;
23
23
24
24
use crate :: errors:: { AddressOfTemporaryTaken , ReturnStmtOutsideOfFnBody , StructExprNonExhaustive } ;
25
25
use rustc_ast as ast;
26
- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
26
+ use rustc_data_structures:: fx:: FxHashMap ;
27
27
use rustc_data_structures:: stack:: ensure_sufficient_stack;
28
28
use rustc_errors:: ErrorReported ;
29
29
use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder , DiagnosticId } ;
@@ -1264,109 +1264,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1264
1264
. emit_err ( StructExprNonExhaustive { span : expr. span , what : adt. variant_descr ( ) } ) ;
1265
1265
}
1266
1266
1267
- let ( error_happened , mut remaining_fields ) = self . check_expr_struct_fields (
1267
+ self . check_expr_struct_fields (
1268
1268
adt_ty,
1269
1269
expected,
1270
1270
expr. hir_id ,
1271
1271
qpath. span ( ) ,
1272
1272
variant,
1273
1273
fields,
1274
- base_expr. is_none ( ) ,
1274
+ base_expr,
1275
1275
expr. span ,
1276
1276
) ;
1277
- if let Some ( base_expr) = base_expr {
1278
- // If check_expr_struct_fields hit an error, do not attempt to populate
1279
- // the fields with the base_expr. This could cause us to hit errors later
1280
- // when certain fields are assumed to exist that in fact do not.
1281
- if !error_happened {
1282
- // FIXME: We are currently creating two branches here in order to maintain
1283
- // consistency. But they should be merged as much as possible.
1284
- if self . tcx . features ( ) . type_changing_struct_update {
1285
- let base_ty = self . check_expr ( base_expr) ;
1286
- match ( adt_ty. kind ( ) , base_ty. kind ( ) ) {
1287
- ( ty:: Adt ( adt, substs) , ty:: Adt ( base_adt, base_subs) ) if adt == base_adt => {
1288
- if !adt. is_struct ( ) {
1289
- self . tcx . sess . emit_err ( FunctionalRecordUpdateOnNonStruct {
1290
- span : base_expr. span ,
1291
- } ) ;
1292
- } ;
1293
- let fru_field_types = variant
1294
- . fields
1295
- . iter ( )
1296
- . map ( |f| {
1297
- let fru_ty = self . normalize_associated_types_in (
1298
- expr. span ,
1299
- self . field_ty ( base_expr. span , f, base_subs) ,
1300
- ) ;
1301
- let ident = self . tcx . adjust_ident ( f. ident , variant. def_id ) ;
1302
- if remaining_fields. remove ( & ident) {
1303
- let target_ty = self . field_ty ( base_expr. span , f, substs) ;
1304
- let cause = self . misc ( base_expr. span ) ;
1305
- match self . at ( & cause, self . param_env ) . sup ( target_ty, fru_ty)
1306
- {
1307
- Ok ( InferOk { obligations, value : ( ) } ) => {
1308
- self . register_predicates ( obligations)
1309
- }
1310
- // FIXME: Needs better diagnostics here
1311
- Err ( _) => self
1312
- . report_mismatched_types (
1313
- & cause,
1314
- target_ty,
1315
- fru_ty,
1316
- FieldMisMatch ( variant. ident . name , ident. name ) ,
1317
- )
1318
- . emit ( ) ,
1319
- }
1320
- }
1321
- fru_ty
1322
- } )
1323
- . collect ( ) ;
1324
-
1325
- self . typeck_results
1326
- . borrow_mut ( )
1327
- . fru_field_types_mut ( )
1328
- . insert ( expr. hir_id , fru_field_types) ;
1329
- }
1330
- _ => {
1331
- self . report_mismatched_types (
1332
- & self . misc ( base_expr. span ) ,
1333
- adt_ty,
1334
- base_ty,
1335
- Mismatch ,
1336
- )
1337
- . emit ( ) ;
1338
- }
1339
- }
1340
- } else {
1341
- self . check_expr_has_type_or_error ( base_expr, adt_ty, |_| { } ) ;
1342
- match adt_ty. kind ( ) {
1343
- ty:: Adt ( adt, substs) if adt. is_struct ( ) => {
1344
- let fru_field_types = adt
1345
- . non_enum_variant ( )
1346
- . fields
1347
- . iter ( )
1348
- . map ( |f| {
1349
- self . normalize_associated_types_in (
1350
- expr. span ,
1351
- f. ty ( self . tcx , substs) ,
1352
- )
1353
- } )
1354
- . collect ( ) ;
1355
-
1356
- self . typeck_results
1357
- . borrow_mut ( )
1358
- . fru_field_types_mut ( )
1359
- . insert ( expr. hir_id , fru_field_types) ;
1360
- }
1361
- _ => {
1362
- self . tcx . sess . emit_err ( FunctionalRecordUpdateOnNonStruct {
1363
- span : base_expr. span ,
1364
- } ) ;
1365
- }
1366
- }
1367
- } ;
1368
- }
1369
- }
1277
+
1370
1278
self . require_type_is_sized ( adt_ty, expr. span , traits:: StructInitializerSized ) ;
1371
1279
adt_ty
1372
1280
}
@@ -1379,9 +1287,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1379
1287
span : Span ,
1380
1288
variant : & ' tcx ty:: VariantDef ,
1381
1289
ast_fields : & ' tcx [ hir:: ExprField < ' tcx > ] ,
1382
- check_completeness : bool ,
1290
+ base_expr : & ' tcx Option < & ' tcx hir :: Expr < ' tcx > > ,
1383
1291
expr_span : Span ,
1384
- ) -> ( bool , FxHashSet < Ident > ) {
1292
+ ) {
1385
1293
let tcx = self . tcx ;
1386
1294
1387
1295
let adt_ty_hint = self
@@ -1456,19 +1364,99 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1456
1364
)
1457
1365
. emit ( ) ;
1458
1366
}
1459
- } else if check_completeness && !error_happened && !remaining_fields. is_empty ( ) {
1367
+ }
1368
+
1369
+ // If check_expr_struct_fields hit an error, do not attempt to populate
1370
+ // the fields with the base_expr. This could cause us to hit errors later
1371
+ // when certain fields are assumed to exist that in fact do not.
1372
+ if error_happened {
1373
+ return ;
1374
+ }
1375
+
1376
+ if let Some ( base_expr) = base_expr {
1377
+ // FIXME: We are currently creating two branches here in order to maintain
1378
+ // consistency. But they should be merged as much as possible.
1379
+ let fru_tys = if self . tcx . features ( ) . type_changing_struct_update {
1380
+ let base_ty = self . check_expr ( base_expr) ;
1381
+ match ( adt_ty. kind ( ) , base_ty. kind ( ) ) {
1382
+ ( ty:: Adt ( adt, substs) , ty:: Adt ( base_adt, base_subs) ) if adt == base_adt => {
1383
+ if !adt. is_struct ( ) {
1384
+ self . tcx . sess . emit_err ( FunctionalRecordUpdateOnNonStruct {
1385
+ span : base_expr. span ,
1386
+ } ) ;
1387
+ } ;
1388
+ variant
1389
+ . fields
1390
+ . iter ( )
1391
+ . map ( |f| {
1392
+ let fru_ty = self . normalize_associated_types_in (
1393
+ expr_span,
1394
+ self . field_ty ( base_expr. span , f, base_subs) ,
1395
+ ) ;
1396
+ let ident = self . tcx . adjust_ident ( f. ident , variant. def_id ) ;
1397
+ if let Some ( _) = remaining_fields. remove ( & ident) {
1398
+ let target_ty = self . field_ty ( base_expr. span , f, substs) ;
1399
+ let cause = self . misc ( base_expr. span ) ;
1400
+ match self . at ( & cause, self . param_env ) . sup ( target_ty, fru_ty) {
1401
+ Ok ( InferOk { obligations, value : ( ) } ) => {
1402
+ self . register_predicates ( obligations)
1403
+ }
1404
+ // FIXME: Need better diagnostics for `FieldMisMatch` error
1405
+ Err ( _) => self
1406
+ . report_mismatched_types (
1407
+ & cause,
1408
+ target_ty,
1409
+ fru_ty,
1410
+ FieldMisMatch ( variant. ident . name , ident. name ) ,
1411
+ )
1412
+ . emit ( ) ,
1413
+ }
1414
+ }
1415
+ fru_ty
1416
+ } )
1417
+ . collect ( )
1418
+ }
1419
+ _ => {
1420
+ return self
1421
+ . report_mismatched_types (
1422
+ & self . misc ( base_expr. span ) ,
1423
+ adt_ty,
1424
+ base_ty,
1425
+ Mismatch ,
1426
+ )
1427
+ . emit ( ) ;
1428
+ }
1429
+ }
1430
+ } else {
1431
+ self . check_expr_has_type_or_error ( base_expr, adt_ty, |_| { } ) ;
1432
+ match adt_ty. kind ( ) {
1433
+ ty:: Adt ( adt, substs) if adt. is_struct ( ) => variant
1434
+ . fields
1435
+ . iter ( )
1436
+ . map ( |f| {
1437
+ self . normalize_associated_types_in ( expr_span, f. ty ( self . tcx , substs) )
1438
+ } )
1439
+ . collect ( ) ,
1440
+ _ => {
1441
+ return self
1442
+ . tcx
1443
+ . sess
1444
+ . emit_err ( FunctionalRecordUpdateOnNonStruct { span : base_expr. span } ) ;
1445
+ }
1446
+ }
1447
+ } ;
1448
+ self . typeck_results . borrow_mut ( ) . fru_field_types_mut ( ) . insert ( expr_id, fru_tys) ;
1449
+ } else if kind_name != "union" && !remaining_fields. is_empty ( ) {
1460
1450
let inaccessible_remaining_fields = remaining_fields. iter ( ) . any ( |( _, ( _, field) ) | {
1461
1451
!field. vis . is_accessible_from ( tcx. parent_module ( expr_id) . to_def_id ( ) , tcx)
1462
1452
} ) ;
1463
1453
1464
1454
if inaccessible_remaining_fields {
1465
1455
self . report_inaccessible_fields ( adt_ty, span) ;
1466
1456
} else {
1467
- self . report_missing_fields ( adt_ty, span, remaining_fields. clone ( ) ) ;
1457
+ self . report_missing_fields ( adt_ty, span, remaining_fields) ;
1468
1458
}
1469
1459
}
1470
-
1471
- ( error_happened, remaining_fields. iter ( ) . map ( |( ident, _) | ident. clone ( ) ) . collect ( ) )
1472
1460
}
1473
1461
1474
1462
fn check_struct_fields_on_error (
0 commit comments