about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSparrowLii <liyuan179@huawei.com>2021-10-29 11:16:28 +0800
committerSparrowLii <liyuan179@huawei.com>2021-10-29 11:16:28 +0800
commitf3679bc23e0ae5998d5f0141a51b3d084fd66eab (patch)
tree6d380a20b4fc03f04e65c65ab02189ca929df75f
parent7bde18a0f3dc52754eb52d09da0bc259b1a0e757 (diff)
downloadrust-f3679bc23e0ae5998d5f0141a51b3d084fd66eab.tar.gz
rust-f3679bc23e0ae5998d5f0141a51b3d084fd66eab.zip
move the processing part of `base_expr` into `check_expr_struct_fields`
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs192
-rw-r--r--src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs2
-rw-r--r--src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr2
3 files changed, 92 insertions, 104 deletions
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 25ad6b659a7..4c7c9ed766d 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -23,7 +23,7 @@ use crate::type_error_struct;
 
 use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
 use rustc_ast as ast;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorReported;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
@@ -1264,109 +1264,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() });
         }
 
-        let (error_happened, mut remaining_fields) = self.check_expr_struct_fields(
+        self.check_expr_struct_fields(
             adt_ty,
             expected,
             expr.hir_id,
             qpath.span(),
             variant,
             fields,
-            base_expr.is_none(),
+            base_expr,
             expr.span,
         );
-        if let Some(base_expr) = base_expr {
-            // If check_expr_struct_fields hit an error, do not attempt to populate
-            // the fields with the base_expr. This could cause us to hit errors later
-            // when certain fields are assumed to exist that in fact do not.
-            if !error_happened {
-                // FIXME: We are currently creating two branches here in order to maintain
-                // consistency. But they should be merged as much as possible.
-                if self.tcx.features().type_changing_struct_update {
-                    let base_ty = self.check_expr(base_expr);
-                    match (adt_ty.kind(), base_ty.kind()) {
-                        (ty::Adt(adt, substs), ty::Adt(base_adt, base_subs)) if adt == base_adt => {
-                            if !adt.is_struct() {
-                                self.tcx.sess.emit_err(FunctionalRecordUpdateOnNonStruct {
-                                    span: base_expr.span,
-                                });
-                            };
-                            let fru_field_types = variant
-                                .fields
-                                .iter()
-                                .map(|f| {
-                                    let fru_ty = self.normalize_associated_types_in(
-                                        expr.span,
-                                        self.field_ty(base_expr.span, f, base_subs),
-                                    );
-                                    let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
-                                    if remaining_fields.remove(&ident) {
-                                        let target_ty = self.field_ty(base_expr.span, f, substs);
-                                        let cause = self.misc(base_expr.span);
-                                        match self.at(&cause, self.param_env).sup(target_ty, fru_ty)
-                                        {
-                                            Ok(InferOk { obligations, value: () }) => {
-                                                self.register_predicates(obligations)
-                                            }
-                                            // FIXME: Needs better diagnostics here
-                                            Err(_) => self
-                                                .report_mismatched_types(
-                                                    &cause,
-                                                    target_ty,
-                                                    fru_ty,
-                                                    FieldMisMatch(variant.ident.name, ident.name),
-                                                )
-                                                .emit(),
-                                        }
-                                    }
-                                    fru_ty
-                                })
-                                .collect();
-
-                            self.typeck_results
-                                .borrow_mut()
-                                .fru_field_types_mut()
-                                .insert(expr.hir_id, fru_field_types);
-                        }
-                        _ => {
-                            self.report_mismatched_types(
-                                &self.misc(base_expr.span),
-                                adt_ty,
-                                base_ty,
-                                Mismatch,
-                            )
-                            .emit();
-                        }
-                    }
-                } else {
-                    self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {});
-                    match adt_ty.kind() {
-                        ty::Adt(adt, substs) if adt.is_struct() => {
-                            let fru_field_types = adt
-                                .non_enum_variant()
-                                .fields
-                                .iter()
-                                .map(|f| {
-                                    self.normalize_associated_types_in(
-                                        expr.span,
-                                        f.ty(self.tcx, substs),
-                                    )
-                                })
-                                .collect();
-
-                            self.typeck_results
-                                .borrow_mut()
-                                .fru_field_types_mut()
-                                .insert(expr.hir_id, fru_field_types);
-                        }
-                        _ => {
-                            self.tcx.sess.emit_err(FunctionalRecordUpdateOnNonStruct {
-                                span: base_expr.span,
-                            });
-                        }
-                    }
-                };
-            }
-        }
+
         self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized);
         adt_ty
     }
@@ -1379,9 +1287,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         variant: &'tcx ty::VariantDef,
         ast_fields: &'tcx [hir::ExprField<'tcx>],
-        check_completeness: bool,
+        base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
         expr_span: Span,
-    ) -> (bool, FxHashSet<Ident>) {
+    ) {
         let tcx = self.tcx;
 
         let adt_ty_hint = self
@@ -1456,7 +1364,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 )
                 .emit();
             }
-        } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
+        }
+
+        // If check_expr_struct_fields hit an error, do not attempt to populate
+        // the fields with the base_expr. This could cause us to hit errors later
+        // when certain fields are assumed to exist that in fact do not.
+        if error_happened {
+            return;
+        }
+
+        if let Some(base_expr) = base_expr {
+            // FIXME: We are currently creating two branches here in order to maintain
+            // consistency. But they should be merged as much as possible.
+            let fru_tys = if self.tcx.features().type_changing_struct_update {
+                let base_ty = self.check_expr(base_expr);
+                match (adt_ty.kind(), base_ty.kind()) {
+                    (ty::Adt(adt, substs), ty::Adt(base_adt, base_subs)) if adt == base_adt => {
+                        if !adt.is_struct() {
+                            self.tcx.sess.emit_err(FunctionalRecordUpdateOnNonStruct {
+                                span: base_expr.span,
+                            });
+                        };
+                        variant
+                            .fields
+                            .iter()
+                            .map(|f| {
+                                let fru_ty = self.normalize_associated_types_in(
+                                    expr_span,
+                                    self.field_ty(base_expr.span, f, base_subs),
+                                );
+                                let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
+                                if let Some(_) = remaining_fields.remove(&ident) {
+                                    let target_ty = self.field_ty(base_expr.span, f, substs);
+                                    let cause = self.misc(base_expr.span);
+                                    match self.at(&cause, self.param_env).sup(target_ty, fru_ty) {
+                                        Ok(InferOk { obligations, value: () }) => {
+                                            self.register_predicates(obligations)
+                                        }
+                                        // FIXME: Need better diagnostics for `FieldMisMatch` error
+                                        Err(_) => self
+                                            .report_mismatched_types(
+                                                &cause,
+                                                target_ty,
+                                                fru_ty,
+                                                FieldMisMatch(variant.ident.name, ident.name),
+                                            )
+                                            .emit(),
+                                    }
+                                }
+                                fru_ty
+                            })
+                            .collect()
+                    }
+                    _ => {
+                        return self
+                            .report_mismatched_types(
+                                &self.misc(base_expr.span),
+                                adt_ty,
+                                base_ty,
+                                Mismatch,
+                            )
+                            .emit();
+                    }
+                }
+            } else {
+                self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {});
+                match adt_ty.kind() {
+                    ty::Adt(adt, substs) if adt.is_struct() => variant
+                        .fields
+                        .iter()
+                        .map(|f| {
+                            self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs))
+                        })
+                        .collect(),
+                    _ => {
+                        return self
+                            .tcx
+                            .sess
+                            .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+                    }
+                }
+            };
+            self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
+        } else if kind_name != "union" && !remaining_fields.is_empty() {
             let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
                 !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
             });
@@ -1464,11 +1454,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if inaccessible_remaining_fields {
                 self.report_inaccessible_fields(adt_ty, span);
             } else {
-                self.report_missing_fields(adt_ty, span, remaining_fields.clone());
+                self.report_missing_fields(adt_ty, span, remaining_fields);
             }
         }
-
-        (error_happened, remaining_fields.iter().map(|(ident, _)| ident.clone()).collect())
     }
 
     fn check_struct_fields_on_error(
diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs
index d05ced724cc..81888ee1d4f 100644
--- a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs
+++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs
@@ -17,11 +17,11 @@ fn update_to_state2() {
         common_field1: "hello",
         common_field2: 2,
     };
+    // FIXME: this should trigger feature gate
     let m2: Machine<State2> = Machine {
         state: State2,
         ..m1 //~ ERROR mismatched types
     };
-    // FIXME: this should trigger feature gate
     assert_eq!(State2, m2.state);
 }
 
diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr
index e45ab02a9b7..19059593844 100644
--- a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr
+++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/feature-gate.rs:22:11
+  --> $DIR/feature-gate.rs:23:11
    |
 LL |         ..m1
    |           ^^ expected struct `State2`, found struct `State1`