@@ -36,11 +36,12 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
36
36
use rustc_infer:: infer:: InferOk ;
37
37
use rustc_middle:: ty;
38
38
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AllowTwoPhase } ;
39
- use rustc_middle:: ty:: error:: TypeError :: { FieldMisMatch , Mismatch } ;
39
+ use rustc_middle:: ty:: error:: TypeError :: FieldMisMatch ;
40
40
use rustc_middle:: ty:: subst:: SubstsRef ;
41
41
use rustc_middle:: ty:: Ty ;
42
42
use rustc_middle:: ty:: TypeFoldable ;
43
43
use rustc_middle:: ty:: { AdtKind , Visibility } ;
44
+ use rustc_session:: parse:: feature_err;
44
45
use rustc_span:: edition:: LATEST_STABLE_EDITION ;
45
46
use rustc_span:: hygiene:: DesugaringKind ;
46
47
use rustc_span:: lev_distance:: find_best_match_for_name;
@@ -1374,78 +1375,124 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1374
1375
}
1375
1376
1376
1377
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
- } ;
1378
+ let expected = if self . tcx . features ( ) . type_changing_struct_update {
1379
+ NoExpectation
1380
+ } else {
1381
+ ExpectHasType ( adt_ty)
1382
+ } ;
1383
+ let mut ty = self . check_expr_with_expectation ( base_expr, expected) ;
1384
+
1385
+ let expected_ty = expected. to_option ( & self ) . unwrap_or ( adt_ty) ;
1386
+ // While we don't allow *arbitrary* coercions here, we *do* allow
1387
+ // coercions from ! to `expected`.
1388
+ if ty. is_never ( ) {
1389
+ assert ! (
1390
+ !self . typeck_results. borrow( ) . adjustments( ) . contains_key( base_expr. hir_id) ,
1391
+ "expression with never type wound up being adjusted"
1392
+ ) ;
1393
+ let adj_ty = self . next_ty_var ( TypeVariableOrigin {
1394
+ kind : TypeVariableOriginKind :: AdjustmentType ,
1395
+ span : base_expr. span ,
1396
+ } ) ;
1397
+ self . apply_adjustments (
1398
+ base_expr,
1399
+ vec ! [ Adjustment { kind: Adjust :: NeverToAny , target: adj_ty } ] ,
1400
+ ) ;
1401
+ ty = adj_ty;
1402
+ }
1403
+ let cause = self . misc ( base_expr. span ) ;
1404
+ let mut fru_tys = None ;
1405
+ let mut err = None ;
1406
+ let is_struct;
1407
+
1408
+ if let ty:: Adt ( adt, substs) = expected_ty. kind ( ) {
1409
+ match ty. kind ( ) {
1410
+ ty:: Adt ( base_adt, base_subs) if adt == base_adt => {
1411
+ if self . tcx . features ( ) . type_changing_struct_update {
1412
+ let tys = variant
1413
+ . fields
1414
+ . iter ( )
1415
+ . map ( |f| {
1416
+ let fru_ty = self . normalize_associated_types_in (
1417
+ expr_span,
1418
+ self . field_ty ( base_expr. span , f, base_subs) ,
1419
+ ) ;
1420
+ let ident = self . tcx . adjust_ident ( f. ident , variant. def_id ) ;
1421
+ if let Some ( _) = remaining_fields. remove ( & ident) {
1422
+ let target_ty = self . field_ty ( base_expr. span , f, substs) ;
1423
+ match self . at ( & cause, self . param_env ) . 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 ( _) => {
1430
+ if err. is_none ( ) {
1431
+ err = Some ( self . report_mismatched_types (
1432
+ & cause,
1433
+ target_ty,
1434
+ fru_ty,
1435
+ FieldMisMatch (
1436
+ variant. ident . name ,
1437
+ ident. name ,
1438
+ ) ,
1439
+ ) )
1440
+ }
1441
+ }
1442
+ }
1443
+ }
1444
+ fru_ty
1445
+ } )
1446
+ . collect ( ) ;
1447
+ fru_tys = Some ( tys) ;
1448
+ } else {
1449
+ err = self . demand_suptype_diag ( base_expr. span , expected_ty, ty) ;
1450
+ if err. is_some ( ) && self . tcx . sess . is_nightly_build ( ) {
1451
+ feature_err (
1452
+ & self . tcx . sess . parse_sess ,
1453
+ sym:: type_changing_struct_update,
1454
+ base_expr. span ,
1455
+ "type changing struct updating is experimental" ,
1456
+ )
1457
+ . emit ( ) ;
1458
+ }
1459
+ }
1460
+ }
1461
+ _ => {
1462
+ err = self . demand_suptype_diag ( base_expr. span , expected_ty, ty) ;
1463
+ }
1464
+ }
1465
+ is_struct = adt. is_struct ( ) ;
1466
+ if is_struct && fru_tys. is_none ( ) {
1467
+ fru_tys = Some (
1388
1468
variant
1389
1469
. fields
1390
1470
. iter ( )
1391
1471
. map ( |f| {
1392
- let fru_ty = self . normalize_associated_types_in (
1472
+ self . normalize_associated_types_in (
1393
1473
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
1474
+ f. ty ( self . tcx , substs) ,
1475
+ )
1416
1476
} )
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
- }
1477
+ . collect ( ) ,
1478
+ )
1429
1479
}
1430
1480
} 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) ;
1481
+ err = self . demand_suptype_diag ( base_expr. span , expected_ty, ty) ;
1482
+ is_struct = false ;
1483
+ }
1484
+ if let Some ( mut err) = err {
1485
+ let expr = base_expr. peel_drop_temps ( ) ;
1486
+ self . suggest_deref_ref_or_into ( & mut err, expr, expected_ty, ty, None ) ;
1487
+ err. emit ( ) ;
1488
+ }
1489
+ if let Some ( fru_tys) = fru_tys {
1490
+ self . typeck_results . borrow_mut ( ) . fru_field_types_mut ( ) . insert ( expr_id, fru_tys) ;
1491
+ }
1492
+ if !is_struct {
1493
+ let e = FunctionalRecordUpdateOnNonStruct { span : base_expr. span } ;
1494
+ self . tcx . sess . emit_err ( e) ;
1495
+ }
1449
1496
} else if kind_name != "union" && !remaining_fields. is_empty ( ) {
1450
1497
let inaccessible_remaining_fields = remaining_fields. iter ( ) . any ( |( _, ( _, field) ) | {
1451
1498
!field. vis . is_accessible_from ( tcx. parent_module ( expr_id) . to_def_id ( ) , tcx)
0 commit comments