@@ -36,11 +36,12 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
3636use rustc_infer:: infer:: InferOk ;
3737use rustc_middle:: ty;
3838use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AllowTwoPhase } ;
39- use rustc_middle:: ty:: error:: TypeError :: { FieldMisMatch , Mismatch } ;
39+ use rustc_middle:: ty:: error:: TypeError :: FieldMisMatch ;
4040use rustc_middle:: ty:: subst:: SubstsRef ;
4141use rustc_middle:: ty:: Ty ;
4242use rustc_middle:: ty:: TypeFoldable ;
4343use rustc_middle:: ty:: { AdtKind , Visibility } ;
44+ use rustc_session:: parse:: feature_err;
4445use rustc_span:: edition:: LATEST_STABLE_EDITION ;
4546use rustc_span:: hygiene:: DesugaringKind ;
4647use rustc_span:: lev_distance:: find_best_match_for_name;
@@ -1374,78 +1375,124 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13741375 }
13751376
13761377 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 (
13881468 variant
13891469 . fields
13901470 . iter ( )
13911471 . map ( |f| {
1392- let fru_ty = self . normalize_associated_types_in (
1472+ self . normalize_associated_types_in (
13931473 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+ )
14161476 } )
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+ )
14291479 }
14301480 } 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+ }
14491496 } else if kind_name != "union" && !remaining_fields. is_empty ( ) {
14501497 let inaccessible_remaining_fields = remaining_fields. iter ( ) . any ( |( _, ( _, field) ) | {
14511498 !field. vis . is_accessible_from ( tcx. parent_module ( expr_id) . to_def_id ( ) , tcx)
0 commit comments