@@ -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 ;
26
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
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 } ;
@@ -33,8 +33,10 @@ use rustc_hir::def_id::DefId;
33
33
use rustc_hir:: { ExprKind , QPath } ;
34
34
use rustc_infer:: infer;
35
35
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
36
+ use rustc_infer:: infer:: InferOk ;
36
37
use rustc_middle:: ty;
37
38
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AllowTwoPhase } ;
39
+ use rustc_middle:: ty:: error:: TypeError :: { FieldMisMatch , Mismatch } ;
38
40
use rustc_middle:: ty:: subst:: SubstsRef ;
39
41
use rustc_middle:: ty:: Ty ;
40
42
use rustc_middle:: ty:: TypeFoldable ;
@@ -1262,7 +1264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1262
1264
. emit_err ( StructExprNonExhaustive { span : expr. span , what : adt. variant_descr ( ) } ) ;
1263
1265
}
1264
1266
1265
- let error_happened = self . check_expr_struct_fields (
1267
+ let ( error_happened, mut remaining_fields ) = self . check_expr_struct_fields (
1266
1268
adt_ty,
1267
1269
expected,
1268
1270
expr. hir_id ,
@@ -1277,32 +1279,92 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1277
1279
// the fields with the base_expr. This could cause us to hit errors later
1278
1280
// when certain fields are assumed to exist that in fact do not.
1279
1281
if !error_happened {
1280
- self . check_expr_has_type_or_error ( base_expr, adt_ty, |_| { } ) ;
1281
- match adt_ty. kind ( ) {
1282
- ty:: Adt ( adt, substs) if adt. is_struct ( ) => {
1283
- let fru_field_types = adt
1284
- . non_enum_variant ( )
1285
- . fields
1286
- . iter ( )
1287
- . map ( |f| {
1288
- self . normalize_associated_types_in (
1289
- expr. span ,
1290
- f. ty ( self . tcx , substs) ,
1291
- )
1292
- } )
1293
- . collect ( ) ;
1294
-
1295
- self . typeck_results
1296
- . borrow_mut ( )
1297
- . fru_field_types_mut ( )
1298
- . insert ( expr. hir_id , fru_field_types) ;
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
+ }
1299
1339
}
1300
- _ => {
1301
- self . tcx
1302
- . sess
1303
- . emit_err ( FunctionalRecordUpdateOnNonStruct { span : base_expr. span } ) ;
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
+ }
1304
1366
}
1305
- }
1367
+ } ;
1306
1368
}
1307
1369
}
1308
1370
self . require_type_is_sized ( adt_ty, expr. span , traits:: StructInitializerSized ) ;
@@ -1319,7 +1381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1319
1381
ast_fields : & ' tcx [ hir:: ExprField < ' tcx > ] ,
1320
1382
check_completeness : bool ,
1321
1383
expr_span : Span ,
1322
- ) -> bool {
1384
+ ) -> ( bool , FxHashSet < Ident > ) {
1323
1385
let tcx = self . tcx ;
1324
1386
1325
1387
let adt_ty_hint = self
@@ -1402,11 +1464,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1402
1464
if inaccessible_remaining_fields {
1403
1465
self . report_inaccessible_fields ( adt_ty, span) ;
1404
1466
} else {
1405
- self . report_missing_fields ( adt_ty, span, remaining_fields) ;
1467
+ self . report_missing_fields ( adt_ty, span, remaining_fields. clone ( ) ) ;
1406
1468
}
1407
1469
}
1408
1470
1409
- error_happened
1471
+ ( error_happened, remaining_fields . iter ( ) . map ( | ( ident , _ ) | ident . clone ( ) ) . collect ( ) )
1410
1472
}
1411
1473
1412
1474
fn check_struct_fields_on_error (
0 commit comments