From 7b457184849d343d50a3eb56c28396189c696a42 Mon Sep 17 00:00:00 2001
From: ouz-a <oguz.agcayazi@gmail.com>
Date: Sat, 13 Aug 2022 18:13:20 +0300
Subject: [PATCH] pass when where clause found

---
 compiler/rustc_typeck/src/check/writeback.rs  | 26 ++++++++-
 src/test/mir-opt/issue-91633.rs               | 31 ++++++++++
 .../mir-opt/issue_91633.bar.mir_map.0.mir     | 39 +++++++++++++
 .../mir-opt/issue_91633.foo.mir_map.0.mir     | 57 +++++++++++++++++++
 .../mir-opt/issue_91633.fun.mir_map.0.mir     | 35 ++++++++++++
 .../mir-opt/issue_91633.hey.mir_map.0.mir     | 35 ++++++++++++
 src/test/ui/typeck/issue-91633.rs             |  8 +++
 7 files changed, 229 insertions(+), 2 deletions(-)
 create mode 100644 src/test/mir-opt/issue-91633.rs
 create mode 100644 src/test/mir-opt/issue_91633.bar.mir_map.0.mir
 create mode 100644 src/test/mir-opt/issue_91633.foo.mir_map.0.mir
 create mode 100644 src/test/mir-opt/issue_91633.fun.mir_map.0.mir
 create mode 100644 src/test/mir-opt/issue_91633.hey.mir_map.0.mir
 create mode 100644 src/test/ui/typeck/issue-91633.rs

diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index f549807c39c91..adcf8ff946d51 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -3,7 +3,6 @@
 // substitutions.
 
 use crate::check::FnCtxt;
-
 use hir::def_id::LocalDefId;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
@@ -16,6 +15,7 @@ use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::TypeckResults;
 use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -192,6 +192,27 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         }
     }
 
+    // (ouz-a 1005988): Normally `[T] : std::ops::Index<usize>` should be normalized
+    // into [T] but currently `Where` clause stops the normalization process for it,
+    // here we compare types of expr and base in a code without `Where` clause they would be equal
+    // if they are not we don't modify the expr, hence we bypass the ICE
+    fn is_builtin_index(
+        &mut self,
+        typeck_results: &TypeckResults<'tcx>,
+        e: &hir::Expr<'_>,
+        base_ty: Ty<'tcx>,
+        index_ty: Ty<'tcx>,
+    ) -> bool {
+        if let Some(elem_ty) = base_ty.builtin_index() {
+            let Some(exp_ty) = typeck_results.expr_ty_opt(e) else {return false;};
+            let resolved_exp_ty = self.resolve(exp_ty, &e.span);
+
+            elem_ty == resolved_exp_ty && index_ty == self.fcx.tcx.types.usize
+        } else {
+            false
+        }
+    }
+
     // Similar to operators, indexing is always assumed to be overloaded
     // Here, correct cases where an indexing expression can be simplified
     // to use builtin indexing because the index type is known to be
@@ -222,8 +243,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                     )
                 });
                 let index_ty = self.fcx.resolve_vars_if_possible(index_ty);
+                let resolved_base_ty = self.resolve(*base_ty, &base.span);
 
-                if base_ty.builtin_index().is_some() && index_ty == self.fcx.tcx.types.usize {
+                if self.is_builtin_index(&typeck_results, e, resolved_base_ty, index_ty) {
                     // Remove the method call record
                     typeck_results.type_dependent_defs_mut().remove(e.hir_id);
                     typeck_results.node_substs_mut().remove(e.hir_id);
diff --git a/src/test/mir-opt/issue-91633.rs b/src/test/mir-opt/issue-91633.rs
new file mode 100644
index 0000000000000..8f66019857fbb
--- /dev/null
+++ b/src/test/mir-opt/issue-91633.rs
@@ -0,0 +1,31 @@
+// compile-flags: -Z mir-opt-level=0
+// EMIT_MIR issue_91633.hey.mir_map.0.mir
+fn hey<T> (it: &[T])
+ where
+     [T] : std::ops::Index<usize>,
+ {
+     let _ = &it[0];
+ }
+
+// EMIT_MIR issue_91633.bar.mir_map.0.mir
+fn bar<T> (it: Box<[T]>)
+ where
+     [T] : std::ops::Index<usize>,
+ {
+     let _ = it[0];
+ }
+
+// EMIT_MIR issue_91633.fun.mir_map.0.mir
+fn fun<T> (it: &[T]) -> &T
+ {
+     let f = &it[0];
+     f
+ }
+
+// EMIT_MIR issue_91633.foo.mir_map.0.mir
+fn foo<T: Clone> (it: Box<[T]>) -> T
+ {
+     let f = it[0].clone();
+     f
+ }
+ fn main(){}
diff --git a/src/test/mir-opt/issue_91633.bar.mir_map.0.mir b/src/test/mir-opt/issue_91633.bar.mir_map.0.mir
new file mode 100644
index 0000000000000..f5092d2ac9238
--- /dev/null
+++ b/src/test/mir-opt/issue_91633.bar.mir_map.0.mir
@@ -0,0 +1,39 @@
+// MIR for `bar` 0 mir_map
+
+fn bar(_1: Box<[T]>) -> () {
+    debug it => _1;                      // in scope 0 at $DIR/issue-91633.rs:+0:12: +0:14
+    let mut _0: ();                      // return place in scope 0 at $DIR/issue-91633.rs:+1:2: +1:2
+    let mut _2: &<[T] as std::ops::Index<usize>>::Output; // in scope 0 at $DIR/issue-91633.rs:+4:14: +4:19
+    let mut _3: &[T];                    // in scope 0 at $DIR/issue-91633.rs:+4:14: +4:16
+    scope 1 {
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-91633.rs:+4:14: +4:19
+        StorageLive(_3);                 // scope 0 at $DIR/issue-91633.rs:+4:14: +4:16
+        _3 = &(*_1);                     // scope 0 at $DIR/issue-91633.rs:+4:14: +4:16
+        _2 = <[T] as Index<usize>>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-91633.rs:+4:14: +4:19
+                                         // mir::Constant
+                                         // + span: $DIR/issue-91633.rs:15:14: 15:19
+                                         // + literal: Const { ty: for<'r> fn(&'r [T], usize) -> &'r <[T] as Index<usize>>::Output {<[T] as Index<usize>>::index}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_3);                 // scope 0 at $DIR/issue-91633.rs:+4:18: +4:19
+        StorageDead(_2);                 // scope 0 at $DIR/issue-91633.rs:+4:19: +4:20
+        _0 = const ();                   // scope 0 at $DIR/issue-91633.rs:+3:2: +5:3
+        drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-91633.rs:+5:2: +5:3
+    }
+
+    bb2: {
+        return;                          // scope 0 at $DIR/issue-91633.rs:+5:3: +5:3
+    }
+
+    bb3 (cleanup): {
+        drop(_1) -> bb4;                 // scope 0 at $DIR/issue-91633.rs:+5:2: +5:3
+    }
+
+    bb4 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-91633.rs:+0:1: +5:3
+    }
+}
diff --git a/src/test/mir-opt/issue_91633.foo.mir_map.0.mir b/src/test/mir-opt/issue_91633.foo.mir_map.0.mir
new file mode 100644
index 0000000000000..2e8b0feedd3f9
--- /dev/null
+++ b/src/test/mir-opt/issue_91633.foo.mir_map.0.mir
@@ -0,0 +1,57 @@
+// MIR for `foo` 0 mir_map
+
+fn foo(_1: Box<[T]>) -> T {
+    debug it => _1;                      // in scope 0 at $DIR/issue-91633.rs:+0:19: +0:21
+    let mut _0: T;                       // return place in scope 0 at $DIR/issue-91633.rs:+0:36: +0:37
+    let _2: T;                           // in scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
+    let mut _3: &T;                      // in scope 0 at $DIR/issue-91633.rs:+2:14: +2:27
+    let _4: usize;                       // in scope 0 at $DIR/issue-91633.rs:+2:17: +2:18
+    let mut _5: usize;                   // in scope 0 at $DIR/issue-91633.rs:+2:14: +2:19
+    let mut _6: bool;                    // in scope 0 at $DIR/issue-91633.rs:+2:14: +2:19
+    scope 1 {
+        debug f => _2;                   // in scope 1 at $DIR/issue-91633.rs:+2:10: +2:11
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
+        StorageLive(_3);                 // scope 0 at $DIR/issue-91633.rs:+2:14: +2:27
+        StorageLive(_4);                 // scope 0 at $DIR/issue-91633.rs:+2:17: +2:18
+        _4 = const 0_usize;              // scope 0 at $DIR/issue-91633.rs:+2:17: +2:18
+        _5 = Len((*_1));                 // scope 0 at $DIR/issue-91633.rs:+2:14: +2:19
+        _6 = Lt(_4, _5);                 // scope 0 at $DIR/issue-91633.rs:+2:14: +2:19
+        assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind: bb5]; // scope 0 at $DIR/issue-91633.rs:+2:14: +2:19
+    }
+
+    bb1: {
+        _3 = &(*_1)[_4];                 // scope 0 at $DIR/issue-91633.rs:+2:14: +2:27
+        _2 = <T as Clone>::clone(move _3) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/issue-91633.rs:+2:14: +2:27
+                                         // mir::Constant
+                                         // + span: $DIR/issue-91633.rs:28:20: 28:25
+                                         // + literal: Const { ty: for<'r> fn(&'r T) -> T {<T as Clone>::clone}, val: Value(<ZST>) }
+    }
+
+    bb2: {
+        StorageDead(_3);                 // scope 0 at $DIR/issue-91633.rs:+2:26: +2:27
+        FakeRead(ForLet(None), _2);      // scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
+        StorageDead(_4);                 // scope 0 at $DIR/issue-91633.rs:+2:27: +2:28
+        _0 = move _2;                    // scope 1 at $DIR/issue-91633.rs:+3:6: +3:7
+        drop(_2) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
+    }
+
+    bb3: {
+        StorageDead(_2);                 // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
+        drop(_1) -> [return: bb4, unwind: bb6]; // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
+    }
+
+    bb4: {
+        return;                          // scope 0 at $DIR/issue-91633.rs:+4:3: +4:3
+    }
+
+    bb5 (cleanup): {
+        drop(_1) -> bb6;                 // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
+    }
+
+    bb6 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-91633.rs:+0:1: +4:3
+    }
+}
diff --git a/src/test/mir-opt/issue_91633.fun.mir_map.0.mir b/src/test/mir-opt/issue_91633.fun.mir_map.0.mir
new file mode 100644
index 0000000000000..ded9a4cf7e3f9
--- /dev/null
+++ b/src/test/mir-opt/issue_91633.fun.mir_map.0.mir
@@ -0,0 +1,35 @@
+// MIR for `fun` 0 mir_map
+
+fn fun(_1: &[T]) -> &T {
+    debug it => _1;                      // in scope 0 at $DIR/issue-91633.rs:+0:12: +0:14
+    let mut _0: &T;                      // return place in scope 0 at $DIR/issue-91633.rs:+0:25: +0:27
+    let _2: &T;                          // in scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
+    let _3: usize;                       // in scope 0 at $DIR/issue-91633.rs:+2:18: +2:19
+    let mut _4: usize;                   // in scope 0 at $DIR/issue-91633.rs:+2:15: +2:20
+    let mut _5: bool;                    // in scope 0 at $DIR/issue-91633.rs:+2:15: +2:20
+    scope 1 {
+        debug f => _2;                   // in scope 1 at $DIR/issue-91633.rs:+2:10: +2:11
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
+        StorageLive(_3);                 // scope 0 at $DIR/issue-91633.rs:+2:18: +2:19
+        _3 = const 0_usize;              // scope 0 at $DIR/issue-91633.rs:+2:18: +2:19
+        _4 = Len((*_1));                 // scope 0 at $DIR/issue-91633.rs:+2:15: +2:20
+        _5 = Lt(_3, _4);                 // scope 0 at $DIR/issue-91633.rs:+2:15: +2:20
+        assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-91633.rs:+2:15: +2:20
+    }
+
+    bb1: {
+        _2 = &(*_1)[_3];                 // scope 0 at $DIR/issue-91633.rs:+2:14: +2:20
+        FakeRead(ForLet(None), _2);      // scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
+        _0 = &(*_2);                     // scope 1 at $DIR/issue-91633.rs:+3:6: +3:7
+        StorageDead(_3);                 // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
+        StorageDead(_2);                 // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
+        return;                          // scope 0 at $DIR/issue-91633.rs:+4:3: +4:3
+    }
+
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-91633.rs:+0:1: +4:3
+    }
+}
diff --git a/src/test/mir-opt/issue_91633.hey.mir_map.0.mir b/src/test/mir-opt/issue_91633.hey.mir_map.0.mir
new file mode 100644
index 0000000000000..74f4a5a976116
--- /dev/null
+++ b/src/test/mir-opt/issue_91633.hey.mir_map.0.mir
@@ -0,0 +1,35 @@
+// MIR for `hey` 0 mir_map
+
+fn hey(_1: &[T]) -> () {
+    debug it => _1;                      // in scope 0 at $DIR/issue-91633.rs:+0:12: +0:14
+    let mut _0: ();                      // return place in scope 0 at $DIR/issue-91633.rs:+1:2: +1:2
+    let mut _2: &<[T] as std::ops::Index<usize>>::Output; // in scope 0 at $DIR/issue-91633.rs:+4:14: +4:20
+    let _3: &<[T] as std::ops::Index<usize>>::Output; // in scope 0 at $DIR/issue-91633.rs:+4:15: +4:20
+    let mut _4: &[T];                    // in scope 0 at $DIR/issue-91633.rs:+4:15: +4:17
+    scope 1 {
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-91633.rs:+4:14: +4:20
+        StorageLive(_3);                 // scope 0 at $DIR/issue-91633.rs:+4:15: +4:20
+        StorageLive(_4);                 // scope 0 at $DIR/issue-91633.rs:+4:15: +4:17
+        _4 = &(*_1);                     // scope 0 at $DIR/issue-91633.rs:+4:15: +4:17
+        _3 = <[T] as Index<usize>>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/issue-91633.rs:+4:15: +4:20
+                                         // mir::Constant
+                                         // + span: $DIR/issue-91633.rs:7:15: 7:20
+                                         // + literal: Const { ty: for<'r> fn(&'r [T], usize) -> &'r <[T] as Index<usize>>::Output {<[T] as Index<usize>>::index}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_4);                 // scope 0 at $DIR/issue-91633.rs:+4:19: +4:20
+        _2 = &(*_3);                     // scope 0 at $DIR/issue-91633.rs:+4:14: +4:20
+        StorageDead(_2);                 // scope 0 at $DIR/issue-91633.rs:+4:20: +4:21
+        _0 = const ();                   // scope 0 at $DIR/issue-91633.rs:+3:2: +5:3
+        StorageDead(_3);                 // scope 0 at $DIR/issue-91633.rs:+5:2: +5:3
+        return;                          // scope 0 at $DIR/issue-91633.rs:+5:3: +5:3
+    }
+
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-91633.rs:+0:1: +5:3
+    }
+}
diff --git a/src/test/ui/typeck/issue-91633.rs b/src/test/ui/typeck/issue-91633.rs
new file mode 100644
index 0000000000000..331a798dd7a36
--- /dev/null
+++ b/src/test/ui/typeck/issue-91633.rs
@@ -0,0 +1,8 @@
+// check-pass
+fn f<T> (it: &[T])
+where
+    [T] : std::ops::Index<usize>,
+{
+    let _ = &it[0];
+}
+fn main(){}