about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-18 13:58:20 +0000
committerbors <bors@rust-lang.org>2023-12-18 13:58:20 +0000
commita7690a366ccb7c7fd6865241792e2199b23c2b5a (patch)
tree8f9f4fc9983cfc7ad0686b74e6b50de208c2a14c
parent3562c535fefe00174cc7fdcace387c9a7f50075e (diff)
parentc3a739e4c8a2bade976794211bbfbe4814fb4c5a (diff)
downloadrust-a7690a366ccb7c7fd6865241792e2199b23c2b5a.tar.gz
rust-a7690a366ccb7c7fd6865241792e2199b23c2b5a.zip
Auto merge of #118584 - gurry:118144-projection-kind-mismatched, r=WaffleLapkin
Fix ICE `ProjectionKinds Deref and Field were mismatched`

Fix #118144

Removed the check that ICEd if the sequence of projection kinds were different across captures. Instead we now sort based only on `Field` projection kinds.
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs60
-rw-r--r--tests/ui/closures/2229_closure_analysis/issue-118144.rs16
-rw-r--r--tests/ui/closures/2229_closure_analysis/issue-118144.stderr11
3 files changed, 51 insertions, 36 deletions
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 69d6fb8e2ea..726ee02d75e 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -680,49 +680,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // `tests/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs`.
         for (_, captures) in &mut root_var_min_capture_list {
             captures.sort_by(|capture1, capture2| {
-                for (p1, p2) in capture1.place.projections.iter().zip(&capture2.place.projections) {
+                fn is_field<'a>(p: &&Projection<'a>) -> bool {
+                    match p.kind {
+                        ProjectionKind::Field(_, _) => true,
+                        ProjectionKind::Deref | ProjectionKind::OpaqueCast => false,
+                        p @ (ProjectionKind::Subslice | ProjectionKind::Index) => {
+                            bug!("ProjectionKind {:?} was unexpected", p)
+                        }
+                    }
+                }
+
+                // Need to sort only by Field projections, so filter away others.
+                // A previous implementation considered other projection types too
+                // but that caused ICE #118144
+                let capture1_field_projections = capture1.place.projections.iter().filter(is_field);
+                let capture2_field_projections = capture2.place.projections.iter().filter(is_field);
+
+                for (p1, p2) in capture1_field_projections.zip(capture2_field_projections) {
                     // We do not need to look at the `Projection.ty` fields here because at each
                     // step of the iteration, the projections will either be the same and therefore
                     // the types must be as well or the current projection will be different and
                     // we will return the result of comparing the field indexes.
                     match (p1.kind, p2.kind) {
-                        // Paths are the same, continue to next loop.
-                        (ProjectionKind::Deref, ProjectionKind::Deref) => {}
-                        (ProjectionKind::OpaqueCast, ProjectionKind::OpaqueCast) => {}
-                        (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
-                            if i1 == i2 => {}
-
-                        // Fields are different, compare them.
                         (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) => {
-                            return i1.cmp(&i2);
+                            // Compare only if paths are different.
+                            // Otherwise continue to the next iteration
+                            if i1 != i2 {
+                                return i1.cmp(&i2);
+                            }
                         }
-
-                        // We should have either a pair of `Deref`s or a pair of `Field`s.
-                        // Anything else is a bug.
-                        (
-                            l @ (ProjectionKind::Deref | ProjectionKind::Field(..)),
-                            r @ (ProjectionKind::Deref | ProjectionKind::Field(..)),
-                        ) => bug!(
-                            "ProjectionKinds Deref and Field were mismatched: ({:?}, {:?})",
-                            l,
-                            r
-                        ),
-                        (
-                            l @ (ProjectionKind::Index
-                            | ProjectionKind::Subslice
-                            | ProjectionKind::Deref
-                            | ProjectionKind::OpaqueCast
-                            | ProjectionKind::Field(..)),
-                            r @ (ProjectionKind::Index
-                            | ProjectionKind::Subslice
-                            | ProjectionKind::Deref
-                            | ProjectionKind::OpaqueCast
-                            | ProjectionKind::Field(..)),
-                        ) => bug!(
-                            "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})",
-                            l,
-                            r
-                        ),
+                        // Given the filter above, this arm should never be hit
+                        (l, r) => bug!("ProjectionKinds {:?} or {:?} were unexpected", l, r),
                     }
                 }
 
diff --git a/tests/ui/closures/2229_closure_analysis/issue-118144.rs b/tests/ui/closures/2229_closure_analysis/issue-118144.rs
new file mode 100644
index 00000000000..3e5d9f9739a
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/issue-118144.rs
@@ -0,0 +1,16 @@
+// Regression test for ICE #118144
+
+struct V(i32);
+
+fn func(func_arg: &mut V) {
+    || {
+        // Declaring `x` separately instead of using
+        // a destructuring binding like `let V(x) = ...`
+        // becaue only `V(x) = ...` triggers the ICE
+        let x;
+        V(x) = func_arg; //~ ERROR: mismatched types
+        func_arg.0 = 0;
+     };
+}
+
+fn main() {}
diff --git a/tests/ui/closures/2229_closure_analysis/issue-118144.stderr b/tests/ui/closures/2229_closure_analysis/issue-118144.stderr
new file mode 100644
index 00000000000..85cb5adc07e
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/issue-118144.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-118144.rs:11:9
+   |
+LL |         V(x) = func_arg;
+   |         ^^^^   -------- this expression has type `&mut V`
+   |         |
+   |         expected `&mut V`, found `V`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.