From 2987f4ba42b002c58ae485f7ae528cb29c3b1611 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Mon, 6 Sep 2021 02:27:41 +0100
Subject: [PATCH 01/18] WIP state

---
 .../rustc_middle/src/mir/abstract_const.rs    |   1 +
 compiler/rustc_mir_build/src/build/mod.rs     |   8 +-
 compiler/rustc_mir_build/src/thir/cx/expr.rs  |   3 +
 compiler/rustc_mir_build/src/thir/cx/mod.rs   |   1 +
 compiler/rustc_privacy/src/lib.rs             |   7 +-
 .../src/traits/const_evaluatable.rs           | 360 +++++++-----------
 .../src/traits/object_safety.rs               |   7 +-
 7 files changed, 160 insertions(+), 227 deletions(-)

diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs
index 1ef10241143b8..e75f084e79e21 100644
--- a/compiler/rustc_middle/src/mir/abstract_const.rs
+++ b/compiler/rustc_middle/src/mir/abstract_const.rs
@@ -17,6 +17,7 @@ pub enum Node<'tcx> {
     Binop(mir::BinOp, NodeId, NodeId),
     UnaryOp(mir::UnOp, NodeId),
     FunctionCall(NodeId, &'tcx [NodeId]),
+    Block(&'tcx [NodeId], Option<NodeId>),
     Cast(CastKind, NodeId, Ty<'tcx>),
 }
 
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 0a760a740dcae..390ce59cb489c 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -28,6 +28,7 @@ crate fn mir_built<'tcx>(
     if let Some(def) = def.try_upgrade(tcx) {
         return tcx.mir_built(def);
     }
+    debug!("mir_built: def={:?}", def);
 
     let mut body = mir_build(tcx, def);
     if def.const_param_did.is_some() {
@@ -40,6 +41,7 @@ crate fn mir_built<'tcx>(
 
 /// Construct the MIR for a given `DefId`.
 fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
+    debug!("mir_build: def={:?}", def);
     let id = tcx.hir().local_def_id_to_hir_id(def.did);
     let body_owner_kind = tcx.hir().body_owner_kind(id);
     let typeck_results = tcx.typeck_opt_const_arg(def);
@@ -47,10 +49,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
     // Ensure unsafeck is ran before we steal the THIR.
     match def {
         ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => {
-            tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did))
+            tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did));
+            tcx.ensure().mir_abstract_const_of_const_arg((did, const_param_did));
         }
         ty::WithOptConstParam { did, const_param_did: None } => {
-            tcx.ensure().thir_check_unsafety(did)
+            tcx.ensure().thir_check_unsafety(did);
+            tcx.ensure().mir_abstract_const(did);
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 66005be05df75..70a5a9286b0b3 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -149,7 +149,9 @@ impl<'tcx> Cx<'tcx> {
     }
 
     fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
+        debug!("Expr::make_mirror_unadjusted: expr={:?}", expr);
         let expr_ty = self.typeck_results().expr_ty(expr);
+        debug!("Expr::make_mirror_unadjusted: expr_ty={:?}", expr_ty);
         let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
 
         let kind = match expr.kind {
@@ -762,6 +764,7 @@ impl<'tcx> Cx<'tcx> {
             hir::ExprKind::Err => unreachable!(),
         };
 
+        debug!("Expr::make_mirror_unadjusted: finish");
         Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 5059dd939d92d..5310efbccd655 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -20,6 +20,7 @@ crate fn thir_body<'tcx>(
     tcx: TyCtxt<'tcx>,
     owner_def: ty::WithOptConstParam<LocalDefId>,
 ) -> (&'tcx Steal<Thir<'tcx>>, ExprId) {
+    debug!("thir_body: {:?}", owner_def);
     let hir = tcx.hir();
     let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(owner_def.did)));
     let mut cx = Cx::new(tcx, owner_def);
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 35e25e52dc5f9..26e1c3e7b8cf4 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -159,9 +159,10 @@ where
                 self.visit_const(leaf)
             }
             ACNode::Cast(_, _, ty) => self.visit_ty(ty),
-            ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
-                ControlFlow::CONTINUE
-            }
+            ACNode::Block(_, _)
+            | ACNode::Binop(..)
+            | ACNode::UnaryOp(..)
+            | ACNode::FunctionCall(_, _) => ControlFlow::CONTINUE,
         })
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index ddabe5967d79c..4e11fefdc81f3 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -8,14 +8,15 @@
 //! In this case we try to build an abstract representation of this constant using
 //! `mir_abstract_const` which can then be checked for structural equality with other
 //! generic constants mentioned in the `caller_bounds` of the current environment.
+use rustc_data_structures::sync::Lrc;
 use rustc_errors::ErrorReported;
 use rustc_hir::def::DefKind;
-use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
+use rustc_middle::mir;
 use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable};
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
+use rustc_middle::thir;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_session::lint;
@@ -101,9 +102,10 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
 
                         ControlFlow::CONTINUE
                     }
-                    Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
-                        ControlFlow::CONTINUE
-                    }
+                    Node::Block(_, _)
+                    | Node::Binop(_, _, _)
+                    | Node::UnaryOp(_, _)
+                    | Node::FunctionCall(_, _) => ControlFlow::CONTINUE,
                 });
 
                 match failure_kind {
@@ -232,7 +234,8 @@ struct WorkNode<'tcx> {
 
 struct AbstractConstBuilder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    body: &'a mir::Body<'tcx>,
+    body_id: thir::ExprId,
+    body: Lrc<&'a thir::Thir<'tcx>>,
     /// The current WIP node tree.
     ///
     /// We require all nodes to be used in the final abstract const,
@@ -240,18 +243,18 @@ struct AbstractConstBuilder<'a, 'tcx> {
     /// if they are mentioned in an assert, so some used nodes are never
     /// actually reachable by walking the [`AbstractConst`].
     nodes: IndexVec<NodeId, WorkNode<'tcx>>,
-    locals: IndexVec<mir::Local, NodeId>,
-    /// We only allow field accesses if they access
-    /// the result of a checked operation.
-    checked_op_locals: BitSet<mir::Local>,
 }
 
 impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
+    fn root_span(&self) -> Span {
+        self.body.exprs[self.body_id].span
+    }
+
     fn error(&mut self, span: Option<Span>, msg: &str) -> Result<!, ErrorReported> {
         self.tcx
             .sess
-            .struct_span_err(self.body.span, "overly complex generic constant")
-            .span_label(span.unwrap_or(self.body.span), msg)
+            .struct_span_err(self.root_span(), "overly complex generic constant")
+            .span_label(span.unwrap_or(self.root_span()), msg)
             .help("consider moving this anonymous constant into a `const` function")
             .emit();
 
@@ -260,28 +263,12 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
 
     fn new(
         tcx: TyCtxt<'tcx>,
-        body: &'a mir::Body<'tcx>,
+        (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId),
     ) -> Result<Option<AbstractConstBuilder<'a, 'tcx>>, ErrorReported> {
-        let mut builder = AbstractConstBuilder {
-            tcx,
-            body,
-            nodes: IndexVec::new(),
-            locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls),
-            checked_op_locals: BitSet::new_empty(body.local_decls.len()),
-        };
-
-        // We don't have to look at concrete constants, as we
-        // can just evaluate them.
-        if !body.is_polymorphic {
-            return Ok(None);
-        }
+        let builder =
+            AbstractConstBuilder { tcx, body_id, body: Lrc::new(body), nodes: IndexVec::new() };
 
-        // We only allow consts without control flow, so
-        // we check for cycles here which simplifies the
-        // rest of this implementation.
-        if body.is_cfg_cyclic() {
-            builder.error(None, "cyclic anonymous constants are forbidden")?;
-        }
+        // FIXME non-constants should return Ok(None)
 
         Ok(Some(builder))
     }
@@ -301,6 +288,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 self.nodes[func].used = true;
                 nodes.iter().for_each(|&n| self.nodes[n].used = true);
             }
+            Node::Block(stmts, opt_expr) => {
+                stmts.iter().for_each(|&id| self.nodes[id].used = true);
+                opt_expr.map(|e| self.nodes[e].used = true);
+            }
             Node::Cast(_, operand, _) => {
                 self.nodes[operand].used = true;
             }
@@ -310,50 +301,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
         self.nodes.push(WorkNode { node, span, used: false })
     }
 
-    fn place_to_local(
-        &mut self,
-        span: Span,
-        p: &mir::Place<'tcx>,
-    ) -> Result<mir::Local, ErrorReported> {
-        const ZERO_FIELD: mir::Field = mir::Field::from_usize(0);
-        // Do not allow any projections.
-        //
-        // One exception are field accesses on the result of checked operations,
-        // which are required to support things like `1 + 2`.
-        if let Some(p) = p.as_local() {
-            debug_assert!(!self.checked_op_locals.contains(p));
-            Ok(p)
-        } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() {
-            // Only allow field accesses if the given local
-            // contains the result of a checked operation.
-            if self.checked_op_locals.contains(p.local) {
-                Ok(p.local)
-            } else {
-                self.error(Some(span), "unsupported projection")?;
-            }
-        } else {
-            self.error(Some(span), "unsupported projection")?;
-        }
-    }
-
-    fn operand_to_node(
-        &mut self,
-        span: Span,
-        op: &mir::Operand<'tcx>,
-    ) -> Result<NodeId, ErrorReported> {
-        debug!("operand_to_node: op={:?}", op);
-        match op {
-            mir::Operand::Copy(p) | mir::Operand::Move(p) => {
-                let local = self.place_to_local(span, p)?;
-                Ok(self.locals[local])
-            }
-            mir::Operand::Constant(ct) => match ct.literal {
-                mir::ConstantKind::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)),
-                mir::ConstantKind::Val(..) => self.error(Some(span), "unsupported constant")?,
-            },
-        }
-    }
-
     /// We do not allow all binary operations in abstract consts, so filter disallowed ones.
     fn check_binop(op: mir::BinOp) -> bool {
         use mir::BinOp::*;
@@ -373,148 +320,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
         }
     }
 
-    fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> {
-        debug!("AbstractConstBuilder: stmt={:?}", stmt);
-        let span = stmt.source_info.span;
-        match stmt.kind {
-            StatementKind::Assign(box (ref place, ref rvalue)) => {
-                let local = self.place_to_local(span, place)?;
-                match *rvalue {
-                    Rvalue::Use(ref operand) => {
-                        self.locals[local] = self.operand_to_node(span, operand)?;
-                        Ok(())
-                    }
-                    Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) if Self::check_binop(op) => {
-                        let lhs = self.operand_to_node(span, lhs)?;
-                        let rhs = self.operand_to_node(span, rhs)?;
-                        self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
-                        if op.is_checkable() {
-                            bug!("unexpected unchecked checkable binary operation");
-                        } else {
-                            Ok(())
-                        }
-                    }
-                    Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs))
-                        if Self::check_binop(op) =>
-                    {
-                        let lhs = self.operand_to_node(span, lhs)?;
-                        let rhs = self.operand_to_node(span, rhs)?;
-                        self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
-                        self.checked_op_locals.insert(local);
-                        Ok(())
-                    }
-                    Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => {
-                        let operand = self.operand_to_node(span, operand)?;
-                        self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
-                        Ok(())
-                    }
-                    Rvalue::Cast(cast_kind, ref operand, ty) => {
-                        let operand = self.operand_to_node(span, operand)?;
-                        self.locals[local] =
-                            self.add_node(Node::Cast(cast_kind, operand, ty), span);
-                        Ok(())
-                    }
-                    _ => self.error(Some(span), "unsupported rvalue")?,
-                }
-            }
-            // These are not actually relevant for us here, so we can ignore them.
-            StatementKind::AscribeUserType(..)
-            | StatementKind::StorageLive(_)
-            | StatementKind::StorageDead(_) => Ok(()),
-            _ => self.error(Some(stmt.source_info.span), "unsupported statement")?,
-        }
-    }
-
-    /// Possible return values:
-    ///
-    /// - `None`: unsupported terminator, stop building
-    /// - `Some(None)`: supported terminator, finish building
-    /// - `Some(Some(block))`: support terminator, build `block` next
-    fn build_terminator(
-        &mut self,
-        terminator: &mir::Terminator<'tcx>,
-    ) -> Result<Option<mir::BasicBlock>, ErrorReported> {
-        debug!("AbstractConstBuilder: terminator={:?}", terminator);
-        match terminator.kind {
-            TerminatorKind::Goto { target } => Ok(Some(target)),
-            TerminatorKind::Return => Ok(None),
-            TerminatorKind::Call {
-                ref func,
-                ref args,
-                destination: Some((ref place, target)),
-                // We do not care about `cleanup` here. Any branch which
-                // uses `cleanup` will fail const-eval and they therefore
-                // do not matter when checking for const evaluatability.
-                //
-                // Do note that even if `panic::catch_unwind` is made const,
-                // we still do not have to care about this, as we do not look
-                // into functions.
-                cleanup: _,
-                // Do not allow overloaded operators for now,
-                // we probably do want to allow this in the future.
-                //
-                // This is currently fairly irrelevant as it requires `const Trait`s.
-                from_hir_call: true,
-                fn_span,
-            } => {
-                let local = self.place_to_local(fn_span, place)?;
-                let func = self.operand_to_node(fn_span, func)?;
-                let args = self.tcx.arena.alloc_from_iter(
-                    args.iter()
-                        .map(|arg| self.operand_to_node(terminator.source_info.span, arg))
-                        .collect::<Result<Vec<NodeId>, _>>()?,
-                );
-                self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span);
-                Ok(Some(target))
-            }
-            TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
-                let p = match cond {
-                    mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
-                    mir::Operand::Constant(_) => bug!("unexpected assert"),
-                };
-
-                const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
-                debug!("proj: {:?}", p.projection);
-                if let Some(p) = p.as_local() {
-                    debug_assert!(!self.checked_op_locals.contains(p));
-                    // Mark locals directly used in asserts as used.
-                    //
-                    // This is needed because division does not use `CheckedBinop` but instead
-                    // adds an explicit assert for `divisor != 0`.
-                    self.nodes[self.locals[p]].used = true;
-                    return Ok(Some(target));
-                } else if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
-                    // Only allow asserts checking the result of a checked operation.
-                    if self.checked_op_locals.contains(p.local) {
-                        return Ok(Some(target));
-                    }
-                }
-
-                self.error(Some(terminator.source_info.span), "unsupported assertion")?;
-            }
-            _ => self.error(Some(terminator.source_info.span), "unsupported terminator")?,
-        }
-    }
-
-    /// Builds the abstract const by walking the mir from start to finish
-    /// and bailing out when encountering an unsupported operation.
+    /// Builds the abstract const by walking the thir and bailing out when
+    /// encountering an unspported operation.
     fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> {
-        let mut block = &self.body.basic_blocks()[mir::START_BLOCK];
-        // We checked for a cyclic cfg above, so this should terminate.
-        loop {
-            debug!("AbstractConstBuilder: block={:?}", block);
-            for stmt in block.statements.iter() {
-                self.build_statement(stmt)?;
-            }
-
-            if let Some(next) = self.build_terminator(block.terminator())? {
-                block = &self.body.basic_blocks()[next];
-            } else {
-                break;
-            }
-        }
+        debug!("Abstractconstbuilder::build: body={:?}", &*self.body);
+        let last = self.recurse_build(self.body_id)?;
+        self.nodes[last].used = true;
 
-        assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap());
         for n in self.nodes.iter() {
             if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n.node {
                 // `AbstractConst`s should not contain any promoteds as they require references which
@@ -523,13 +335,108 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             }
         }
 
-        self.nodes[self.locals[mir::RETURN_PLACE]].used = true;
         if let Some(&unused) = self.nodes.iter().find(|n| !n.used) {
             self.error(Some(unused.span), "dead code")?;
         }
 
         Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node)))
     }
+
+    fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorReported> {
+        use thir::ExprKind;
+        let node = &self.body.clone().exprs[node];
+        debug!("recurse_build: node={:?}", node);
+        Ok(match &node.kind {
+            // I dont know if handling of these 3 is correct
+            &ExprKind::Scope { value, .. } => self.recurse_build(value)?,
+            &ExprKind::PlaceTypeAscription { source, .. } |
+            &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
+
+            &ExprKind::Literal { literal, .. }
+            | &ExprKind::StaticRef { literal, .. } => self.add_node(Node::Leaf(literal), node.span),
+
+            // FIXME(generic_const_exprs) handle `from_hir_call` field
+            ExprKind::Call { fun, args,  .. } => {
+                let fun = self.recurse_build(*fun)?;
+
+                let mut new_args = Vec::<NodeId>::with_capacity(args.len());
+                for &id in args.iter() {
+                    new_args.push(self.recurse_build(id)?);
+                }
+                let new_args = self.tcx.arena.alloc_slice(&new_args);
+                self.add_node(Node::FunctionCall(fun, new_args), node.span)
+            },
+            &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => {
+                let lhs = self.recurse_build(lhs)?;
+                let rhs = self.recurse_build(rhs)?;
+                self.add_node(Node::Binop(op, lhs, rhs), node.span)
+            }
+            &ExprKind::Unary { op, arg } if Self::check_unop(op) => {
+                let arg = self.recurse_build(arg)?;
+                self.add_node(Node::UnaryOp(op, arg), node.span)
+            },
+            // HACK: without this arm the following doesn't compile:
+            // ```
+            // fn foo<const N: usize>(_: [(); N + 1]) {
+            //     bar::<{ N + 1}>();
+            // }
+            // ```
+            // we ought to properly handle this in `try_unify`
+            ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?,
+            ExprKind::Block { body } => {
+                let mut stmts = Vec::with_capacity(body.stmts.len());
+                for &id in body.stmts.iter() {
+                    match &self.body.stmts[id].kind {
+                        thir::StmtKind::Let { .. } => return self.error(
+                                Some(node.span),
+                                "let statements are not supported in generic constants",
+                            ).map(|never| never),
+                        thir::StmtKind::Expr { expr, .. } => stmts.push(self.recurse_build(*expr)?),
+                    }
+                };
+                let stmts = self.tcx.arena.alloc_slice(&stmts);
+                let opt_expr = body.expr.map(|e| self.recurse_build(e)).transpose()?;
+                self.add_node(Node::Block(stmts, opt_expr), node.span)
+            }
+            &ExprKind::Cast { source } => todo!(),
+            // never can arise even without panic/fail to terminate
+            &ExprKind::NeverToAny { source } => todo!(),
+            // i think this is a dummy usage of the expr to allow coercions
+            &ExprKind::Use { source } => todo!(),
+
+            ExprKind::Return { .. }
+            | ExprKind::Box { .. } // allocations not allowed in constants
+            | ExprKind::AssignOp { .. }
+            | ExprKind::AddressOf { .. } // FIXME(generic_const_exprs)
+            | ExprKind::Borrow { .. } // FIXME(generic_const_exprs)
+            | ExprKind::Deref { .. } // FIXME(generic_const_exprs)
+            | ExprKind::Repeat { .. } // FIXME(generic_const_exprs)
+            | ExprKind::Array { .. } // FIXME(generic_const_exprs)
+            | ExprKind::Tuple { .. } // FIXME(generic_const_exprs)
+            | ExprKind::Index { .. } // FIXME(generic_const_exprs)
+            | ExprKind::Field { .. } // FIXME(generic_const_exprs)
+            | ExprKind::ConstBlock { .. } // FIXME(generic_const_exprs)
+            | ExprKind::Adt(_) // FIXME(generic_const_exprs) we *should* permit this but dont currently
+            | ExprKind::Match { .. }
+            | ExprKind::VarRef { .. } //
+            | ExprKind::UpvarRef { .. } // we dont permit let stmts so...
+            | ExprKind::Closure { .. }
+            | ExprKind::Let { .. } // let expressions imply control flow
+            | ExprKind::Loop { .. }
+            | ExprKind::Assign { .. }
+            | ExprKind::LogicalOp { .. }
+            | ExprKind::Unary { .. } //
+            | ExprKind::Binary { .. } // we handle valid unary/binary ops above 
+            | ExprKind::Break { .. }
+            | ExprKind::Continue { .. }
+            | ExprKind::If { .. }
+            | ExprKind::Pointer { .. } // dont know if this is correct
+            | ExprKind::ThreadLocalRef(_)
+            | ExprKind::LlvmInlineAsm { .. }
+            | ExprKind::InlineAsm { .. }
+            | ExprKind::Yield { .. } => return self.error(Some(node.span), "unsupported operation in generic constant").map(|never| never),
+        })
+    }
 }
 
 /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
@@ -547,8 +454,17 @@ pub(super) fn mir_abstract_const<'tcx>(
             DefKind::AnonConst => (),
             _ => return Ok(None),
         }
-        let body = tcx.mir_const(def).borrow();
-        AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose()
+        debug!("mir_abstract_const: {:?}", def);
+        let body = tcx.thir_body(def);
+
+        if body.0.borrow().exprs.is_empty() {
+            // type error in constant, there is no thir
+            return Err(ErrorReported);
+        }
+
+        AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))?
+            .map(AbstractConstBuilder::build)
+            .transpose()
     } else {
         Ok(None)
     }
@@ -599,6 +515,12 @@ where
                 recurse(tcx, ct.subtree(func), f)?;
                 args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
             }
+            Node::Block(stmts, opt_expr) => {
+                for id in stmts.iter().copied().chain(opt_expr) {
+                    recurse(tcx, ct.subtree(id), f)?;
+                }
+                ControlFlow::CONTINUE
+            }
             Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 57b8a84300ff9..e64cc9e4b8f28 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -844,9 +844,10 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
                         self.visit_const(leaf)
                     }
                     Node::Cast(_, _, ty) => self.visit_ty(ty),
-                    Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
-                        ControlFlow::CONTINUE
-                    }
+                    Node::Block(_, _)
+                    | Node::Binop(..)
+                    | Node::UnaryOp(..)
+                    | Node::FunctionCall(_, _) => ControlFlow::CONTINUE,
                 })
             } else {
                 ControlFlow::CONTINUE

From 9b2913814b95e1b8f123da59ddecb1bc6b3813af Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Mon, 6 Sep 2021 16:14:01 +0100
Subject: [PATCH 02/18] as casts and block exprs

---
 .../rustc_middle/src/mir/abstract_const.rs    |  4 +-
 compiler/rustc_privacy/src/lib.rs             |  2 +-
 .../src/traits/const_evaluatable.rs           | 84 ++++++++++++-------
 .../src/traits/object_safety.rs               |  2 +-
 4 files changed, 57 insertions(+), 35 deletions(-)

diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs
index e75f084e79e21..1158a9f4f8008 100644
--- a/compiler/rustc_middle/src/mir/abstract_const.rs
+++ b/compiler/rustc_middle/src/mir/abstract_const.rs
@@ -1,5 +1,5 @@
 //! A subset of a mir body used for const evaluatability checking.
-use crate::mir::{self, CastKind};
+use crate::mir;
 use crate::ty::{self, Ty};
 
 rustc_index::newtype_index! {
@@ -18,7 +18,7 @@ pub enum Node<'tcx> {
     UnaryOp(mir::UnOp, NodeId),
     FunctionCall(NodeId, &'tcx [NodeId]),
     Block(&'tcx [NodeId], Option<NodeId>),
-    Cast(CastKind, NodeId, Ty<'tcx>),
+    Cast(NodeId, Ty<'tcx>),
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 26e1c3e7b8cf4..7d0f6767900a3 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -158,7 +158,7 @@ where
                 let leaf = leaf.subst(tcx, ct.substs);
                 self.visit_const(leaf)
             }
-            ACNode::Cast(_, _, ty) => self.visit_ty(ty),
+            ACNode::Cast(_, ty) => self.visit_ty(ty),
             ACNode::Block(_, _)
             | ACNode::Binop(..)
             | ACNode::UnaryOp(..)
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 4e11fefdc81f3..461ebba58d985 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -92,7 +92,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
 
                         ControlFlow::CONTINUE
                     }
-                    Node::Cast(_, _, ty) => {
+                    Node::Cast(_, ty) => {
                         let ty = ty.subst(tcx, ct.substs);
                         if ty.has_infer_types_or_consts() {
                             failure_kind = FailureKind::MentionsInfer;
@@ -292,7 +292,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 stmts.iter().for_each(|&id| self.nodes[id].used = true);
                 opt_expr.map(|e| self.nodes[e].used = true);
             }
-            Node::Cast(_, operand, _) => {
+            Node::Cast(operand, _) => {
                 self.nodes[operand].used = true;
             }
         }
@@ -335,6 +335,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             }
         }
 
+        // FIXME I dont even think we can get unused nodes anymore with thir abstract const
         if let Some(&unused) = self.nodes.iter().find(|n| !n.used) {
             self.error(Some(unused.span), "dead code")?;
         }
@@ -352,6 +353,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             &ExprKind::PlaceTypeAscription { source, .. } |
             &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
 
+            // subtle: associated consts are literals this arm handles 
+            // `<T as Trait>::ASSOC` as well as `12` 
             &ExprKind::Literal { literal, .. }
             | &ExprKind::StaticRef { literal, .. } => self.add_node(Node::Leaf(literal), node.span),
 
@@ -375,14 +378,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 let arg = self.recurse_build(arg)?;
                 self.add_node(Node::UnaryOp(op, arg), node.span)
             },
-            // HACK: without this arm the following doesn't compile:
-            // ```
-            // fn foo<const N: usize>(_: [(); N + 1]) {
-            //     bar::<{ N + 1}>();
-            // }
-            // ```
-            // we ought to properly handle this in `try_unify`
-            ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?,
             ExprKind::Block { body } => {
                 let mut stmts = Vec::with_capacity(body.stmts.len());
                 for &id in body.stmts.iter() {
@@ -398,26 +393,34 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 let opt_expr = body.expr.map(|e| self.recurse_build(e)).transpose()?;
                 self.add_node(Node::Block(stmts, opt_expr), node.span)
             }
-            &ExprKind::Cast { source } => todo!(),
+            
+            // ExprKind::Use happens when a `hir::ExprKind::Cast` is a 
+            // "coercion cast" i.e. using a coercion or is a no-op.
+            // this is important so that `N as usize as usize` doesnt unify with `N as usize`
+            &ExprKind::Use { source} 
+            | &ExprKind::Cast { source } => {
+                let arg = self.recurse_build(source)?;
+                self.add_node(Node::Cast(arg, node.ty), node.span)
+            },
             // never can arise even without panic/fail to terminate
             &ExprKind::NeverToAny { source } => todo!(),
-            // i think this is a dummy usage of the expr to allow coercions
-            &ExprKind::Use { source } => todo!(),
 
-            ExprKind::Return { .. }
-            | ExprKind::Box { .. } // allocations not allowed in constants
-            | ExprKind::AssignOp { .. }
-            | ExprKind::AddressOf { .. } // FIXME(generic_const_exprs)
-            | ExprKind::Borrow { .. } // FIXME(generic_const_exprs)
-            | ExprKind::Deref { .. } // FIXME(generic_const_exprs)
-            | ExprKind::Repeat { .. } // FIXME(generic_const_exprs)
-            | ExprKind::Array { .. } // FIXME(generic_const_exprs)
-            | ExprKind::Tuple { .. } // FIXME(generic_const_exprs)
-            | ExprKind::Index { .. } // FIXME(generic_const_exprs)
-            | ExprKind::Field { .. } // FIXME(generic_const_exprs)
-            | ExprKind::ConstBlock { .. } // FIXME(generic_const_exprs)
-            | ExprKind::Adt(_) // FIXME(generic_const_exprs) we *should* permit this but dont currently
-            | ExprKind::Match { .. }
+            // FIXME(generic_const_exprs) we want to support these
+            ExprKind::AddressOf { .. }
+            | ExprKind::Borrow { .. }
+            | ExprKind::Deref { .. }
+            | ExprKind::Repeat { .. }
+            | ExprKind::Array { .. }
+            | ExprKind::Tuple { .. }
+            | ExprKind::Index { .. }
+            | ExprKind::Field { .. }
+            | ExprKind::ConstBlock { .. }
+            | ExprKind::Adt(_) => return self.error(
+                    Some(node.span), 
+                    "unsupported operation in generic constant, this may be supported in the future",
+                ).map(|never| never),
+
+            ExprKind::Match { .. }
             | ExprKind::VarRef { .. } //
             | ExprKind::UpvarRef { .. } // we dont permit let stmts so...
             | ExprKind::Closure { .. }
@@ -433,6 +436,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             | ExprKind::Pointer { .. } // dont know if this is correct
             | ExprKind::ThreadLocalRef(_)
             | ExprKind::LlvmInlineAsm { .. }
+            | ExprKind::Return { .. }
+            | ExprKind::Box { .. } // allocations not allowed in constants
+            | ExprKind::AssignOp { .. }
             | ExprKind::InlineAsm { .. }
             | ExprKind::Yield { .. } => return self.error(Some(node.span), "unsupported operation in generic constant").map(|never| never),
         })
@@ -521,7 +527,7 @@ where
                 }
                 ControlFlow::CONTINUE
             }
-            Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
+            Node::Cast(operand, _) => recurse(tcx, ct.subtree(operand), f),
         }
     }
 
@@ -604,11 +610,27 @@ pub(super) fn try_unify<'tcx>(
                 && iter::zip(a_args, b_args)
                     .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
         }
-        (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty))
-            if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) =>
+        (Node::Cast(a_operand, a_ty), Node::Cast(b_operand, b_ty))
+            if (a_ty == b_ty) =>
         {
             try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
         }
-        _ => false,
+        (Node::Block(a_stmts, a_opt_expr), Node::Block(b_stmts, b_opt_expr))
+            if a_stmts.len() == b_stmts.len() => {
+            a_stmts.iter().zip(b_stmts.iter()).all(|(&a_stmt, &b_stmt)| {
+                try_unify(tcx, a.subtree(a_stmt), b.subtree(b_stmt))
+            }) && match (a_opt_expr, b_opt_expr) {
+                (Some(a_expr), Some(b_expr)) => try_unify(tcx, a.subtree(a_expr), b.subtree(b_expr)),
+                (None, None) => true,
+                _ => false,
+            }
+        }
+        // use this over `_ => false` to make adding variants to `Node` less error prone
+        (Node::Block(..), _) 
+        | (Node::Cast(..), _) 
+        | (Node::FunctionCall(..), _) 
+        | (Node::UnaryOp(..), _) 
+        | (Node::Binop(..), _) 
+        | (Node::Leaf(..), _) => false,
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index e64cc9e4b8f28..3527aede609a4 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -843,7 +843,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
                         let leaf = leaf.subst(self.tcx, ct.substs);
                         self.visit_const(leaf)
                     }
-                    Node::Cast(_, _, ty) => self.visit_ty(ty),
+                    Node::Cast(_, ty) => self.visit_ty(ty),
                     Node::Block(_, _)
                     | Node::Binop(..)
                     | Node::UnaryOp(..)

From 4483c2bdf64e213627998ac7e2340de7dafb3037 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Mon, 6 Sep 2021 18:20:09 +0100
Subject: [PATCH 03/18] dont support blocks

---
 .../rustc_middle/src/mir/abstract_const.rs    |  1 -
 compiler/rustc_privacy/src/lib.rs             |  3 +-
 .../src/traits/const_evaluatable.rs           | 51 ++++---------------
 .../src/traits/object_safety.rs               |  3 +-
 .../generic_const_exprs/unused_expr.stderr    | 12 ++---
 5 files changed, 16 insertions(+), 54 deletions(-)

diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs
index 1158a9f4f8008..27849e4bdb0bf 100644
--- a/compiler/rustc_middle/src/mir/abstract_const.rs
+++ b/compiler/rustc_middle/src/mir/abstract_const.rs
@@ -17,7 +17,6 @@ pub enum Node<'tcx> {
     Binop(mir::BinOp, NodeId, NodeId),
     UnaryOp(mir::UnOp, NodeId),
     FunctionCall(NodeId, &'tcx [NodeId]),
-    Block(&'tcx [NodeId], Option<NodeId>),
     Cast(NodeId, Ty<'tcx>),
 }
 
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 7d0f6767900a3..02ea34ea9743f 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -159,8 +159,7 @@ where
                 self.visit_const(leaf)
             }
             ACNode::Cast(_, ty) => self.visit_ty(ty),
-            ACNode::Block(_, _)
-            | ACNode::Binop(..)
+            ACNode::Binop(..)
             | ACNode::UnaryOp(..)
             | ACNode::FunctionCall(_, _) => ControlFlow::CONTINUE,
         })
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 461ebba58d985..77fe1f514d901 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -102,8 +102,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
 
                         ControlFlow::CONTINUE
                     }
-                    Node::Block(_, _)
-                    | Node::Binop(_, _, _)
+                    Node::Binop(_, _, _)
                     | Node::UnaryOp(_, _)
                     | Node::FunctionCall(_, _) => ControlFlow::CONTINUE,
                 });
@@ -288,10 +287,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 self.nodes[func].used = true;
                 nodes.iter().for_each(|&n| self.nodes[n].used = true);
             }
-            Node::Block(stmts, opt_expr) => {
-                stmts.iter().for_each(|&id| self.nodes[id].used = true);
-                opt_expr.map(|e| self.nodes[e].used = true);
-            }
             Node::Cast(operand, _) => {
                 self.nodes[operand].used = true;
             }
@@ -378,22 +373,14 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 let arg = self.recurse_build(arg)?;
                 self.add_node(Node::UnaryOp(op, arg), node.span)
             },
-            ExprKind::Block { body } => {
-                let mut stmts = Vec::with_capacity(body.stmts.len());
-                for &id in body.stmts.iter() {
-                    match &self.body.stmts[id].kind {
-                        thir::StmtKind::Let { .. } => return self.error(
-                                Some(node.span),
-                                "let statements are not supported in generic constants",
-                            ).map(|never| never),
-                        thir::StmtKind::Expr { expr, .. } => stmts.push(self.recurse_build(*expr)?),
-                    }
-                };
-                let stmts = self.tcx.arena.alloc_slice(&stmts);
-                let opt_expr = body.expr.map(|e| self.recurse_build(e)).transpose()?;
-                self.add_node(Node::Block(stmts, opt_expr), node.span)
-            }
-            
+            // this is necessary so that the following compiles:
+            //
+            // ```
+            // fn foo<const N: usize>(a: [(); N + 1]) {
+            //     bar::<{ N + 1 }>();
+            // }
+            // ```
+            ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?,
             // ExprKind::Use happens when a `hir::ExprKind::Cast` is a 
             // "coercion cast" i.e. using a coercion or is a no-op.
             // this is important so that `N as usize as usize` doesnt unify with `N as usize`
@@ -411,6 +398,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             | ExprKind::Deref { .. }
             | ExprKind::Repeat { .. }
             | ExprKind::Array { .. }
+            | ExprKind::Block { .. }
             | ExprKind::Tuple { .. }
             | ExprKind::Index { .. }
             | ExprKind::Field { .. }
@@ -521,12 +509,6 @@ where
                 recurse(tcx, ct.subtree(func), f)?;
                 args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
             }
-            Node::Block(stmts, opt_expr) => {
-                for id in stmts.iter().copied().chain(opt_expr) {
-                    recurse(tcx, ct.subtree(id), f)?;
-                }
-                ControlFlow::CONTINUE
-            }
             Node::Cast(operand, _) => recurse(tcx, ct.subtree(operand), f),
         }
     }
@@ -615,19 +597,8 @@ pub(super) fn try_unify<'tcx>(
         {
             try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
         }
-        (Node::Block(a_stmts, a_opt_expr), Node::Block(b_stmts, b_opt_expr))
-            if a_stmts.len() == b_stmts.len() => {
-            a_stmts.iter().zip(b_stmts.iter()).all(|(&a_stmt, &b_stmt)| {
-                try_unify(tcx, a.subtree(a_stmt), b.subtree(b_stmt))
-            }) && match (a_opt_expr, b_opt_expr) {
-                (Some(a_expr), Some(b_expr)) => try_unify(tcx, a.subtree(a_expr), b.subtree(b_expr)),
-                (None, None) => true,
-                _ => false,
-            }
-        }
         // use this over `_ => false` to make adding variants to `Node` less error prone
-        (Node::Block(..), _) 
-        | (Node::Cast(..), _) 
+        (Node::Cast(..), _) 
         | (Node::FunctionCall(..), _) 
         | (Node::UnaryOp(..), _) 
         | (Node::Binop(..), _) 
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 3527aede609a4..d9ea259155358 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -844,8 +844,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
                         self.visit_const(leaf)
                     }
                     Node::Cast(_, ty) => self.visit_ty(ty),
-                    Node::Block(_, _)
-                    | Node::Binop(..)
+                    Node::Binop(..)
                     | Node::UnaryOp(..)
                     | Node::FunctionCall(_, _) => ControlFlow::CONTINUE,
                 })
diff --git a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr
index 1687dbbcbe3f8..3da91b19a5ed9 100644
--- a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr
@@ -2,9 +2,7 @@ error: overly complex generic constant
   --> $DIR/unused_expr.rs:4:34
    |
 LL | fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
-   |                                  ^^-----^^^^^
-   |                                    |
-   |                                    dead code
+   |                                  ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
@@ -12,9 +10,7 @@ error: overly complex generic constant
   --> $DIR/unused_expr.rs:9:34
    |
 LL | fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
-   |                                  ^^-----^^^^^
-   |                                    |
-   |                                    dead code
+   |                                  ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
@@ -22,9 +18,7 @@ error: overly complex generic constant
   --> $DIR/unused_expr.rs:16:38
    |
 LL | fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
-   |                                      ^^------^^^^^
-   |                                        |
-   |                                        dead code
+   |                                      ^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 

From 47b16f4ac9145538e8375d2625181df281206be7 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Mon, 6 Sep 2021 18:41:05 +0100
Subject: [PATCH 04/18] bless stderr

---
 .../array-size-in-generic-struct-param.full.stderr        | 2 +-
 .../ui/const-generics/generic_const_exprs/closures.stderr | 2 +-
 .../generic_const_exprs/let-bindings.stderr               | 8 ++------
 src/test/ui/const-generics/issues/issue-67375.full.stderr | 6 +++---
 .../ui/const-generics/issues/issue-67945-2.full.stderr    | 3 +--
 5 files changed, 8 insertions(+), 13 deletions(-)

diff --git a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr
index deb6f3bd12c1d..9b3c32a939779 100644
--- a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr
@@ -10,7 +10,7 @@ error: overly complex generic constant
   --> $DIR/array-size-in-generic-struct-param.rs:19:15
    |
 LL |     arr: [u8; CFG.arr_size],
-   |               ^^^^^^^^^^^^ unsupported projection
+   |               ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr
index 9f0b7252e8326..95dae4ecc0431 100644
--- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr
@@ -4,7 +4,7 @@ error: overly complex generic constant
 LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
    |                                   ^^^^-------^^
    |                                       |
-   |                                       unsupported rvalue
+   |                                       unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr
index 5749defb3e12c..c9f847995223a 100644
--- a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr
@@ -2,9 +2,7 @@ error: overly complex generic constant
   --> $DIR/let-bindings.rs:6:68
    |
 LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
-   |                                                                    ^^^^^^-^^^^^^^^^^^^^
-   |                                                                          |
-   |                                                                          unsupported statement
+   |                                                                    ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
@@ -12,9 +10,7 @@ error: overly complex generic constant
   --> $DIR/let-bindings.rs:6:35
    |
 LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
-   |                                   ^^^^^^-^^^^^^^^^^^^^
-   |                                         |
-   |                                         unsupported statement
+   |                                   ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/src/test/ui/const-generics/issues/issue-67375.full.stderr b/src/test/ui/const-generics/issues/issue-67375.full.stderr
index 5386ef56a245a..d7b52063dc4db 100644
--- a/src/test/ui/const-generics/issues/issue-67375.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-67375.full.stderr
@@ -2,9 +2,9 @@ error: overly complex generic constant
   --> $DIR/issue-67375.rs:7:17
    |
 LL |     inner: [(); { [|_: &T| {}; 0].len() }],
-   |                 ^^^----------^^^^^^^^^^^^
-   |                    |
-   |                    unsupported rvalue
+   |                 ^^---------------^^^^^^^^
+   |                   |
+   |                   unsupported operation in generic constant
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr
index 118cf447c01e2..fe0351a829220 100644
--- a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr
@@ -5,11 +5,10 @@ LL |       A: [(); {
    |  _____________^
 LL | |
 LL | |         let x: Option<Box<Self>> = None;
-   | |                                    ---- unsupported rvalue
 LL | |
 LL | |         0
 LL | |     }],
-   | |_____^
+   | |_____^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 

From c170dcf04c62ffd79cbf28f340aaf6824e70f493 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Mon, 6 Sep 2021 23:18:25 +0100
Subject: [PATCH 05/18] tidy

---
 compiler/rustc_privacy/src/lib.rs             |  6 ++--
 .../src/traits/const_evaluatable.rs           | 30 +++++++++----------
 .../src/traits/object_safety.rs               |  6 ++--
 3 files changed, 20 insertions(+), 22 deletions(-)

diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 02ea34ea9743f..910249ecc479e 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -159,9 +159,9 @@ where
                 self.visit_const(leaf)
             }
             ACNode::Cast(_, ty) => self.visit_ty(ty),
-            ACNode::Binop(..)
-            | ACNode::UnaryOp(..)
-            | ACNode::FunctionCall(_, _) => ControlFlow::CONTINUE,
+            ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
+                ControlFlow::CONTINUE
+            }
         })
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 77fe1f514d901..7d69ec54bdf02 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -102,9 +102,9 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
 
                         ControlFlow::CONTINUE
                     }
-                    Node::Binop(_, _, _)
-                    | Node::UnaryOp(_, _)
-                    | Node::FunctionCall(_, _) => ControlFlow::CONTINUE,
+                    Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
+                        ControlFlow::CONTINUE
+                    }
                 });
 
                 match failure_kind {
@@ -348,8 +348,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             &ExprKind::PlaceTypeAscription { source, .. } |
             &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
 
-            // subtle: associated consts are literals this arm handles 
-            // `<T as Trait>::ASSOC` as well as `12` 
+            // subtle: associated consts are literals this arm handles
+            // `<T as Trait>::ASSOC` as well as `12`
             &ExprKind::Literal { literal, .. }
             | &ExprKind::StaticRef { literal, .. } => self.add_node(Node::Leaf(literal), node.span),
 
@@ -381,10 +381,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             // }
             // ```
             ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?,
-            // ExprKind::Use happens when a `hir::ExprKind::Cast` is a 
+            // ExprKind::Use happens when a `hir::ExprKind::Cast` is a
             // "coercion cast" i.e. using a coercion or is a no-op.
             // this is important so that `N as usize as usize` doesnt unify with `N as usize`
-            &ExprKind::Use { source} 
+            &ExprKind::Use { source}
             | &ExprKind::Cast { source } => {
                 let arg = self.recurse_build(source)?;
                 self.add_node(Node::Cast(arg, node.ty), node.span)
@@ -404,7 +404,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             | ExprKind::Field { .. }
             | ExprKind::ConstBlock { .. }
             | ExprKind::Adt(_) => return self.error(
-                    Some(node.span), 
+                    Some(node.span),
                     "unsupported operation in generic constant, this may be supported in the future",
                 ).map(|never| never),
 
@@ -417,7 +417,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             | ExprKind::Assign { .. }
             | ExprKind::LogicalOp { .. }
             | ExprKind::Unary { .. } //
-            | ExprKind::Binary { .. } // we handle valid unary/binary ops above 
+            | ExprKind::Binary { .. } // we handle valid unary/binary ops above
             | ExprKind::Break { .. }
             | ExprKind::Continue { .. }
             | ExprKind::If { .. }
@@ -592,16 +592,14 @@ pub(super) fn try_unify<'tcx>(
                 && iter::zip(a_args, b_args)
                     .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
         }
-        (Node::Cast(a_operand, a_ty), Node::Cast(b_operand, b_ty))
-            if (a_ty == b_ty) =>
-        {
+        (Node::Cast(a_operand, a_ty), Node::Cast(b_operand, b_ty)) if (a_ty == b_ty) => {
             try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
         }
         // use this over `_ => false` to make adding variants to `Node` less error prone
-        (Node::Cast(..), _) 
-        | (Node::FunctionCall(..), _) 
-        | (Node::UnaryOp(..), _) 
-        | (Node::Binop(..), _) 
+        (Node::Cast(..), _)
+        | (Node::FunctionCall(..), _)
+        | (Node::UnaryOp(..), _)
+        | (Node::Binop(..), _)
         | (Node::Leaf(..), _) => false,
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index d9ea259155358..63bd10994b1ac 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -844,9 +844,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
                         self.visit_const(leaf)
                     }
                     Node::Cast(_, ty) => self.visit_ty(ty),
-                    Node::Binop(..)
-                    | Node::UnaryOp(..)
-                    | Node::FunctionCall(_, _) => ControlFlow::CONTINUE,
+                    Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
+                        ControlFlow::CONTINUE
+                    }
                 })
             } else {
                 ControlFlow::CONTINUE

From 08e86440165619c57e0072eb742c7dad3cfd0950 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 00:05:24 +0100
Subject: [PATCH 06/18] move thir visitor to rustc_middle

---
 compiler/rustc_middle/src/thir.rs             | 243 ++++++++++++++++++
 .../rustc_mir_build/src/check_unsafety.rs     |   2 +-
 compiler/rustc_mir_build/src/thir/mod.rs      |   1 -
 compiler/rustc_mir_build/src/thir/visit.rs    | 240 -----------------
 4 files changed, 244 insertions(+), 242 deletions(-)
 delete mode 100644 compiler/rustc_mir_build/src/thir/visit.rs

diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 91a64e163e7c0..3012676c872bd 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -818,3 +818,246 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
         }
     }
 }
+
+pub mod visit {
+    use super::*;
+    pub trait Visitor<'a, 'tcx: 'a>: Sized {
+        fn thir(&self) -> &'a Thir<'tcx>;
+
+        fn visit_expr(&mut self, expr: &Expr<'tcx>) {
+            walk_expr(self, expr);
+        }
+
+        fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
+            walk_stmt(self, stmt);
+        }
+
+        fn visit_block(&mut self, block: &Block) {
+            walk_block(self, block);
+        }
+
+        fn visit_arm(&mut self, arm: &Arm<'tcx>) {
+            walk_arm(self, arm);
+        }
+
+        fn visit_pat(&mut self, pat: &Pat<'tcx>) {
+            walk_pat(self, pat);
+        }
+
+        fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
+    }
+
+    pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
+        use ExprKind::*;
+        match expr.kind {
+            Scope { value, region_scope: _, lint_level: _ } => {
+                visitor.visit_expr(&visitor.thir()[value])
+            }
+            Box { value } => visitor.visit_expr(&visitor.thir()[value]),
+            If { cond, then, else_opt, if_then_scope: _ } => {
+                visitor.visit_expr(&visitor.thir()[cond]);
+                visitor.visit_expr(&visitor.thir()[then]);
+                if let Some(else_expr) = else_opt {
+                    visitor.visit_expr(&visitor.thir()[else_expr]);
+                }
+            }
+            Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
+                visitor.visit_expr(&visitor.thir()[fun]);
+                for &arg in &**args {
+                    visitor.visit_expr(&visitor.thir()[arg]);
+                }
+            }
+            Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
+            Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
+                visitor.visit_expr(&visitor.thir()[lhs]);
+                visitor.visit_expr(&visitor.thir()[rhs]);
+            }
+            Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+            Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
+            Use { source } => visitor.visit_expr(&visitor.thir()[source]),
+            NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
+            Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
+            Let { expr, .. } => {
+                visitor.visit_expr(&visitor.thir()[expr]);
+            }
+            Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
+            Match { scrutinee, ref arms } => {
+                visitor.visit_expr(&visitor.thir()[scrutinee]);
+                for &arm in &**arms {
+                    visitor.visit_arm(&visitor.thir()[arm]);
+                }
+            }
+            Block { ref body } => visitor.visit_block(body),
+            Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
+                visitor.visit_expr(&visitor.thir()[lhs]);
+                visitor.visit_expr(&visitor.thir()[rhs]);
+            }
+            Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
+            Index { lhs, index } => {
+                visitor.visit_expr(&visitor.thir()[lhs]);
+                visitor.visit_expr(&visitor.thir()[index]);
+            }
+            VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
+            Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+            AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+            Break { value, label: _ } => {
+                if let Some(value) = value {
+                    visitor.visit_expr(&visitor.thir()[value])
+                }
+            }
+            Continue { label: _ } => {}
+            Return { value } => {
+                if let Some(value) = value {
+                    visitor.visit_expr(&visitor.thir()[value])
+                }
+            }
+            ConstBlock { value } => visitor.visit_const(value),
+            Repeat { value, count } => {
+                visitor.visit_expr(&visitor.thir()[value]);
+                visitor.visit_const(count);
+            }
+            Array { ref fields } | Tuple { ref fields } => {
+                for &field in &**fields {
+                    visitor.visit_expr(&visitor.thir()[field]);
+                }
+            }
+            Adt(box crate::thir::Adt {
+                ref fields,
+                ref base,
+                adt_def: _,
+                variant_index: _,
+                substs: _,
+                user_ty: _,
+            }) => {
+                for field in &**fields {
+                    visitor.visit_expr(&visitor.thir()[field.expr]);
+                }
+                if let Some(base) = base {
+                    visitor.visit_expr(&visitor.thir()[base.base]);
+                }
+            }
+            PlaceTypeAscription { source, user_ty: _ }
+            | ValueTypeAscription { source, user_ty: _ } => {
+                visitor.visit_expr(&visitor.thir()[source])
+            }
+            Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
+            Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
+            StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
+            InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
+                for op in &**operands {
+                    use InlineAsmOperand::*;
+                    match op {
+                        In { expr, reg: _ }
+                        | Out { expr: Some(expr), reg: _, late: _ }
+                        | InOut { expr, reg: _, late: _ }
+                        | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]),
+                        SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
+                            visitor.visit_expr(&visitor.thir()[*in_expr]);
+                            if let Some(out_expr) = out_expr {
+                                visitor.visit_expr(&visitor.thir()[*out_expr]);
+                            }
+                        }
+                        Out { expr: None, reg: _, late: _ }
+                        | Const { value: _, span: _ }
+                        | SymStatic { def_id: _ } => {}
+                    }
+                }
+            }
+            ThreadLocalRef(_) => {}
+            LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
+                for &out_expr in &**outputs {
+                    visitor.visit_expr(&visitor.thir()[out_expr]);
+                }
+                for &in_expr in &**inputs {
+                    visitor.visit_expr(&visitor.thir()[in_expr]);
+                }
+            }
+            Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
+        }
+    }
+
+    pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
+        match &stmt.kind {
+            StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
+            StmtKind::Let {
+                initializer,
+                remainder_scope: _,
+                init_scope: _,
+                ref pattern,
+                lint_level: _,
+            } => {
+                if let Some(init) = initializer {
+                    visitor.visit_expr(&visitor.thir()[*init]);
+                }
+                visitor.visit_pat(pattern);
+            }
+        }
+    }
+
+    pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) {
+        for &stmt in &*block.stmts {
+            visitor.visit_stmt(&visitor.thir()[stmt]);
+        }
+        if let Some(expr) = block.expr {
+            visitor.visit_expr(&visitor.thir()[expr]);
+        }
+    }
+
+    pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) {
+        match arm.guard {
+            Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]),
+            Some(Guard::IfLet(ref pat, expr)) => {
+                visitor.visit_pat(pat);
+                visitor.visit_expr(&visitor.thir()[expr]);
+            }
+            None => {}
+        }
+        visitor.visit_pat(&arm.pattern);
+        visitor.visit_expr(&visitor.thir()[arm.body]);
+    }
+
+    pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) {
+        use PatKind::*;
+        match pat.kind.as_ref() {
+            AscribeUserType { subpattern, ascription: _ }
+            | Deref { subpattern }
+            | Binding {
+                subpattern: Some(subpattern),
+                mutability: _,
+                mode: _,
+                var: _,
+                ty: _,
+                is_primary: _,
+                name: _,
+            } => visitor.visit_pat(&subpattern),
+            Binding { .. } | Wild => {}
+            Variant { subpatterns, adt_def: _, substs: _, variant_index: _ }
+            | Leaf { subpatterns } => {
+                for subpattern in subpatterns {
+                    visitor.visit_pat(&subpattern.pattern);
+                }
+            }
+            Constant { value } => visitor.visit_const(value),
+            Range(range) => {
+                visitor.visit_const(range.lo);
+                visitor.visit_const(range.hi);
+            }
+            Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
+                for subpattern in prefix {
+                    visitor.visit_pat(&subpattern);
+                }
+                if let Some(pat) = slice {
+                    visitor.visit_pat(pat);
+                }
+                for subpattern in suffix {
+                    visitor.visit_pat(&subpattern);
+                }
+            }
+            Or { pats } => {
+                for pat in pats {
+                    visitor.visit_pat(&pat);
+                }
+            }
+        };
+    }
+}
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 05a5fcef16ae5..0e82b18720142 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -1,5 +1,5 @@
 use crate::build::ExprCategory;
-use crate::thir::visit::{self, Visitor};
+use rustc_middle::thir::visit::{self, Visitor};
 
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index e5123d8ef0c99..ddbe1b0b69c1e 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -11,4 +11,3 @@ crate mod cx;
 crate mod pattern;
 
 mod util;
-pub mod visit;
diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_mir_build/src/thir/visit.rs
deleted file mode 100644
index 51c371b872057..0000000000000
--- a/compiler/rustc_mir_build/src/thir/visit.rs
+++ /dev/null
@@ -1,240 +0,0 @@
-use rustc_middle::thir::{self, *};
-use rustc_middle::ty::Const;
-
-pub trait Visitor<'a, 'tcx: 'a>: Sized {
-    fn thir(&self) -> &'a Thir<'tcx>;
-
-    fn visit_expr(&mut self, expr: &Expr<'tcx>) {
-        walk_expr(self, expr);
-    }
-
-    fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
-        walk_stmt(self, stmt);
-    }
-
-    fn visit_block(&mut self, block: &Block) {
-        walk_block(self, block);
-    }
-
-    fn visit_arm(&mut self, arm: &Arm<'tcx>) {
-        walk_arm(self, arm);
-    }
-
-    fn visit_pat(&mut self, pat: &Pat<'tcx>) {
-        walk_pat(self, pat);
-    }
-
-    fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
-}
-
-pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
-    use ExprKind::*;
-    match expr.kind {
-        Scope { value, region_scope: _, lint_level: _ } => {
-            visitor.visit_expr(&visitor.thir()[value])
-        }
-        Box { value } => visitor.visit_expr(&visitor.thir()[value]),
-        If { cond, then, else_opt, if_then_scope: _ } => {
-            visitor.visit_expr(&visitor.thir()[cond]);
-            visitor.visit_expr(&visitor.thir()[then]);
-            if let Some(else_expr) = else_opt {
-                visitor.visit_expr(&visitor.thir()[else_expr]);
-            }
-        }
-        Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
-            visitor.visit_expr(&visitor.thir()[fun]);
-            for &arg in &**args {
-                visitor.visit_expr(&visitor.thir()[arg]);
-            }
-        }
-        Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
-        Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
-            visitor.visit_expr(&visitor.thir()[lhs]);
-            visitor.visit_expr(&visitor.thir()[rhs]);
-        }
-        Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
-        Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
-        Use { source } => visitor.visit_expr(&visitor.thir()[source]),
-        NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
-        Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
-        Let { expr, .. } => {
-            visitor.visit_expr(&visitor.thir()[expr]);
-        }
-        Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
-        Match { scrutinee, ref arms } => {
-            visitor.visit_expr(&visitor.thir()[scrutinee]);
-            for &arm in &**arms {
-                visitor.visit_arm(&visitor.thir()[arm]);
-            }
-        }
-        Block { ref body } => visitor.visit_block(body),
-        Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
-            visitor.visit_expr(&visitor.thir()[lhs]);
-            visitor.visit_expr(&visitor.thir()[rhs]);
-        }
-        Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
-        Index { lhs, index } => {
-            visitor.visit_expr(&visitor.thir()[lhs]);
-            visitor.visit_expr(&visitor.thir()[index]);
-        }
-        VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
-        Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]),
-        AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
-        Break { value, label: _ } => {
-            if let Some(value) = value {
-                visitor.visit_expr(&visitor.thir()[value])
-            }
-        }
-        Continue { label: _ } => {}
-        Return { value } => {
-            if let Some(value) = value {
-                visitor.visit_expr(&visitor.thir()[value])
-            }
-        }
-        ConstBlock { value } => visitor.visit_const(value),
-        Repeat { value, count } => {
-            visitor.visit_expr(&visitor.thir()[value]);
-            visitor.visit_const(count);
-        }
-        Array { ref fields } | Tuple { ref fields } => {
-            for &field in &**fields {
-                visitor.visit_expr(&visitor.thir()[field]);
-            }
-        }
-        Adt(box thir::Adt {
-            ref fields,
-            ref base,
-            adt_def: _,
-            variant_index: _,
-            substs: _,
-            user_ty: _,
-        }) => {
-            for field in &**fields {
-                visitor.visit_expr(&visitor.thir()[field.expr]);
-            }
-            if let Some(base) = base {
-                visitor.visit_expr(&visitor.thir()[base.base]);
-            }
-        }
-        PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => {
-            visitor.visit_expr(&visitor.thir()[source])
-        }
-        Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
-        Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
-        StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
-        InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
-            for op in &**operands {
-                use InlineAsmOperand::*;
-                match op {
-                    In { expr, reg: _ }
-                    | Out { expr: Some(expr), reg: _, late: _ }
-                    | InOut { expr, reg: _, late: _ }
-                    | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]),
-                    SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
-                        visitor.visit_expr(&visitor.thir()[*in_expr]);
-                        if let Some(out_expr) = out_expr {
-                            visitor.visit_expr(&visitor.thir()[*out_expr]);
-                        }
-                    }
-                    Out { expr: None, reg: _, late: _ }
-                    | Const { value: _, span: _ }
-                    | SymStatic { def_id: _ } => {}
-                }
-            }
-        }
-        ThreadLocalRef(_) => {}
-        LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
-            for &out_expr in &**outputs {
-                visitor.visit_expr(&visitor.thir()[out_expr]);
-            }
-            for &in_expr in &**inputs {
-                visitor.visit_expr(&visitor.thir()[in_expr]);
-            }
-        }
-        Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
-    }
-}
-
-pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
-    match &stmt.kind {
-        StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
-        StmtKind::Let {
-            initializer,
-            remainder_scope: _,
-            init_scope: _,
-            ref pattern,
-            lint_level: _,
-        } => {
-            if let Some(init) = initializer {
-                visitor.visit_expr(&visitor.thir()[*init]);
-            }
-            visitor.visit_pat(pattern);
-        }
-    }
-}
-
-pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) {
-    for &stmt in &*block.stmts {
-        visitor.visit_stmt(&visitor.thir()[stmt]);
-    }
-    if let Some(expr) = block.expr {
-        visitor.visit_expr(&visitor.thir()[expr]);
-    }
-}
-
-pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) {
-    match arm.guard {
-        Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]),
-        Some(Guard::IfLet(ref pat, expr)) => {
-            visitor.visit_pat(pat);
-            visitor.visit_expr(&visitor.thir()[expr]);
-        }
-        None => {}
-    }
-    visitor.visit_pat(&arm.pattern);
-    visitor.visit_expr(&visitor.thir()[arm.body]);
-}
-
-pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) {
-    use PatKind::*;
-    match pat.kind.as_ref() {
-        AscribeUserType { subpattern, ascription: _ }
-        | Deref { subpattern }
-        | Binding {
-            subpattern: Some(subpattern),
-            mutability: _,
-            mode: _,
-            var: _,
-            ty: _,
-            is_primary: _,
-            name: _,
-        } => visitor.visit_pat(&subpattern),
-        Binding { .. } | Wild => {}
-        Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } | Leaf { subpatterns } => {
-            for subpattern in subpatterns {
-                visitor.visit_pat(&subpattern.pattern);
-            }
-        }
-        Constant { value } => visitor.visit_const(value),
-        Range(range) => {
-            visitor.visit_const(range.lo);
-            visitor.visit_const(range.hi);
-        }
-        Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
-            for subpattern in prefix {
-                visitor.visit_pat(&subpattern);
-            }
-            if let Some(pat) = slice {
-                visitor.visit_pat(pat);
-            }
-            for subpattern in suffix {
-                visitor.visit_pat(&subpattern);
-            }
-        }
-        Or { pats } => {
-            for pat in pats {
-                visitor.visit_pat(&pat);
-            }
-        }
-    };
-}

From fc63e9a8fb619ad79d2d24db06078652a2a6c1ba Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 00:05:59 +0100
Subject: [PATCH 07/18] dont build abstract const for monomorphic consts

---
 .../src/traits/const_evaluatable.rs           | 31 ++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 7d69ec54bdf02..3e1719e08acfa 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -267,7 +267,36 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
         let builder =
             AbstractConstBuilder { tcx, body_id, body: Lrc::new(body), nodes: IndexVec::new() };
 
-        // FIXME non-constants should return Ok(None)
+        struct IsThirPolymorphic<'a, 'tcx> {
+            is_poly: bool,
+            thir: &'a thir::Thir<'tcx>,
+            tcx: TyCtxt<'tcx>,
+        }
+
+        use thir::visit;
+        impl<'a, 'tcx: 'a> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> {
+            fn thir(&self) -> &'a thir::Thir<'tcx> {
+                &self.thir
+            }
+
+            fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) {
+                self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx);
+                if self.is_poly {
+                    return;
+                }
+                visit::walk_expr(self, expr);
+            }
+
+            fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) {
+                self.is_poly |= ct.definitely_has_param_types_or_consts(self.tcx);
+            }
+        }
+
+        let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx };
+        visit::walk_expr(&mut is_poly_vis, &body[body_id]);
+        if is_poly_vis.is_poly == false {
+            return Ok(None);
+        }
 
         Ok(Some(builder))
     }

From 4cbcb0936a3ae16a99f977427a6a01646a1ed8dd Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 00:06:44 +0100
Subject: [PATCH 08/18] handle `ExprKind::NeverToAny`

---
 compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 3e1719e08acfa..21423d415e3b9 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -418,8 +418,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 let arg = self.recurse_build(source)?;
                 self.add_node(Node::Cast(arg, node.ty), node.span)
             },
-            // never can arise even without panic/fail to terminate
-            &ExprKind::NeverToAny { source } => todo!(),
 
             // FIXME(generic_const_exprs) we want to support these
             ExprKind::AddressOf { .. }
@@ -428,6 +426,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             | ExprKind::Repeat { .. }
             | ExprKind::Array { .. }
             | ExprKind::Block { .. }
+            | ExprKind::NeverToAny { .. } // I dont think we can get this without adt construction
             | ExprKind::Tuple { .. }
             | ExprKind::Index { .. }
             | ExprKind::Field { .. }

From 1f57f8b9032fa0f83aa59f634ac72f1e63a1cfa2 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 00:44:24 +0100
Subject: [PATCH 09/18] remove `WorkNode`

---
 .../src/traits/const_evaluatable.rs           | 61 +++----------------
 1 file changed, 10 insertions(+), 51 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 21423d415e3b9..c47b0c31ca01c 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -224,24 +224,13 @@ impl<'tcx> AbstractConst<'tcx> {
     }
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-struct WorkNode<'tcx> {
-    node: Node<'tcx>,
-    span: Span,
-    used: bool,
-}
-
 struct AbstractConstBuilder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body_id: thir::ExprId,
+    /// `Lrc` is used to avoid borrowck difficulties in `recurse_build`
     body: Lrc<&'a thir::Thir<'tcx>>,
     /// The current WIP node tree.
-    ///
-    /// We require all nodes to be used in the final abstract const,
-    /// so we store this here. Note that we also consider nodes as used
-    /// if they are mentioned in an assert, so some used nodes are never
-    /// actually reachable by walking the [`AbstractConst`].
-    nodes: IndexVec<NodeId, WorkNode<'tcx>>,
+    nodes: IndexVec<NodeId, Node<'tcx>>,
 }
 
 impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
@@ -301,30 +290,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
         Ok(Some(builder))
     }
 
-    fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId {
-        // Mark used nodes.
-        match node {
-            Node::Leaf(_) => (),
-            Node::Binop(_, lhs, rhs) => {
-                self.nodes[lhs].used = true;
-                self.nodes[rhs].used = true;
-            }
-            Node::UnaryOp(_, input) => {
-                self.nodes[input].used = true;
-            }
-            Node::FunctionCall(func, nodes) => {
-                self.nodes[func].used = true;
-                nodes.iter().for_each(|&n| self.nodes[n].used = true);
-            }
-            Node::Cast(operand, _) => {
-                self.nodes[operand].used = true;
-            }
-        }
-
-        // Nodes start as unused.
-        self.nodes.push(WorkNode { node, span, used: false })
-    }
-
     /// We do not allow all binary operations in abstract consts, so filter disallowed ones.
     fn check_binop(op: mir::BinOp) -> bool {
         use mir::BinOp::*;
@@ -348,23 +313,17 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
     /// encountering an unspported operation.
     fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> {
         debug!("Abstractconstbuilder::build: body={:?}", &*self.body);
-        let last = self.recurse_build(self.body_id)?;
-        self.nodes[last].used = true;
+        self.recurse_build(self.body_id)?;
 
         for n in self.nodes.iter() {
-            if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n.node {
+            if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n {
                 // `AbstractConst`s should not contain any promoteds as they require references which
                 // are not allowed.
                 assert_eq!(ct.promoted, None);
             }
         }
 
-        // FIXME I dont even think we can get unused nodes anymore with thir abstract const
-        if let Some(&unused) = self.nodes.iter().find(|n| !n.used) {
-            self.error(Some(unused.span), "dead code")?;
-        }
-
-        Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node)))
+        Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter()))
     }
 
     fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorReported> {
@@ -380,7 +339,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             // subtle: associated consts are literals this arm handles
             // `<T as Trait>::ASSOC` as well as `12`
             &ExprKind::Literal { literal, .. }
-            | &ExprKind::StaticRef { literal, .. } => self.add_node(Node::Leaf(literal), node.span),
+            | &ExprKind::StaticRef { literal, .. } => self.nodes.push(Node::Leaf(literal)),
 
             // FIXME(generic_const_exprs) handle `from_hir_call` field
             ExprKind::Call { fun, args,  .. } => {
@@ -391,16 +350,16 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                     new_args.push(self.recurse_build(id)?);
                 }
                 let new_args = self.tcx.arena.alloc_slice(&new_args);
-                self.add_node(Node::FunctionCall(fun, new_args), node.span)
+                self.nodes.push(Node::FunctionCall(fun, new_args))
             },
             &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => {
                 let lhs = self.recurse_build(lhs)?;
                 let rhs = self.recurse_build(rhs)?;
-                self.add_node(Node::Binop(op, lhs, rhs), node.span)
+                self.nodes.push(Node::Binop(op, lhs, rhs))
             }
             &ExprKind::Unary { op, arg } if Self::check_unop(op) => {
                 let arg = self.recurse_build(arg)?;
-                self.add_node(Node::UnaryOp(op, arg), node.span)
+                self.nodes.push(Node::UnaryOp(op, arg))
             },
             // this is necessary so that the following compiles:
             //
@@ -416,7 +375,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             &ExprKind::Use { source}
             | &ExprKind::Cast { source } => {
                 let arg = self.recurse_build(source)?;
-                self.add_node(Node::Cast(arg, node.ty), node.span)
+                self.nodes.push(Node::Cast(arg, node.ty))
             },
 
             // FIXME(generic_const_exprs) we want to support these

From 15101c8e95db6941f8c7d55fb301ad1b62748c7b Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 01:17:51 +0100
Subject: [PATCH 10/18] remove debug stmts

---
 compiler/rustc_mir_build/src/build/mod.rs                      | 2 --
 compiler/rustc_mir_build/src/thir/cx/expr.rs                   | 3 ---
 compiler/rustc_mir_build/src/thir/cx/mod.rs                    | 1 -
 compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 3 +--
 4 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 390ce59cb489c..e931c686dde59 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -28,7 +28,6 @@ crate fn mir_built<'tcx>(
     if let Some(def) = def.try_upgrade(tcx) {
         return tcx.mir_built(def);
     }
-    debug!("mir_built: def={:?}", def);
 
     let mut body = mir_build(tcx, def);
     if def.const_param_did.is_some() {
@@ -41,7 +40,6 @@ crate fn mir_built<'tcx>(
 
 /// Construct the MIR for a given `DefId`.
 fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
-    debug!("mir_build: def={:?}", def);
     let id = tcx.hir().local_def_id_to_hir_id(def.did);
     let body_owner_kind = tcx.hir().body_owner_kind(id);
     let typeck_results = tcx.typeck_opt_const_arg(def);
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 70a5a9286b0b3..66005be05df75 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -149,9 +149,7 @@ impl<'tcx> Cx<'tcx> {
     }
 
     fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
-        debug!("Expr::make_mirror_unadjusted: expr={:?}", expr);
         let expr_ty = self.typeck_results().expr_ty(expr);
-        debug!("Expr::make_mirror_unadjusted: expr_ty={:?}", expr_ty);
         let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
 
         let kind = match expr.kind {
@@ -764,7 +762,6 @@ impl<'tcx> Cx<'tcx> {
             hir::ExprKind::Err => unreachable!(),
         };
 
-        debug!("Expr::make_mirror_unadjusted: finish");
         Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 5310efbccd655..5059dd939d92d 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -20,7 +20,6 @@ crate fn thir_body<'tcx>(
     tcx: TyCtxt<'tcx>,
     owner_def: ty::WithOptConstParam<LocalDefId>,
 ) -> (&'tcx Steal<Thir<'tcx>>, ExprId) {
-    debug!("thir_body: {:?}", owner_def);
     let hir = tcx.hir();
     let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(owner_def.did)));
     let mut cx = Cx::new(tcx, owner_def);
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index c47b0c31ca01c..4251dc5e93904 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -435,9 +435,8 @@ pub(super) fn mir_abstract_const<'tcx>(
             DefKind::AnonConst => (),
             _ => return Ok(None),
         }
-        debug!("mir_abstract_const: {:?}", def);
+        
         let body = tcx.thir_body(def);
-
         if body.0.borrow().exprs.is_empty() {
             // type error in constant, there is no thir
             return Err(ErrorReported);

From 406d2ab95de0e90f45e00f6c1be1e4e7912aa153 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 01:56:29 +0100
Subject: [PATCH 11/18] rename mir -> thir around abstract consts

---
 compiler/rustc_metadata/src/rmeta/decoder.rs  |   9 +-
 .../src/rmeta/decoder/cstore_impl.rs          |   2 +-
 compiler/rustc_metadata/src/rmeta/encoder.rs  |   8 +-
 compiler/rustc_metadata/src/rmeta/mod.rs      |   3 +-
 compiler/rustc_middle/src/mir/mod.rs          |   1 -
 compiler/rustc_middle/src/mir/query.rs        |   9 +-
 compiler/rustc_middle/src/query/mod.rs        |   8 +-
 compiler/rustc_middle/src/thir.rs             | 246 +-----------------
 .../src/{mir => thir}/abstract_const.rs       |   0
 compiler/rustc_middle/src/thir/visit.rs       | 238 +++++++++++++++++
 compiler/rustc_middle/src/traits/mod.rs       |   2 +-
 compiler/rustc_middle/src/ty/codec.rs         |   5 +-
 compiler/rustc_mir_build/src/build/mod.rs     |   4 +-
 compiler/rustc_mir_transform/src/lib.rs       |   1 -
 compiler/rustc_privacy/src/lib.rs             |   2 +-
 .../rustc_query_impl/src/on_disk_cache.rs     |   3 +-
 .../src/traits/const_evaluatable.rs           |  12 +-
 .../src/traits/error_reporting/mod.rs         |   2 +-
 .../src/traits/fulfill.rs                     |   2 +-
 .../rustc_trait_selection/src/traits/mod.rs   |  10 +-
 .../src/traits/object_safety.rs               |   2 +-
 .../src/traits/select/mod.rs                  |   2 +-
 22 files changed, 287 insertions(+), 284 deletions(-)
 rename compiler/rustc_middle/src/{mir => thir}/abstract_const.rs (100%)
 create mode 100644 compiler/rustc_middle/src/thir/visit.rs

diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index dd44e0cb1fa90..7ebea9ecc8ef2 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -26,6 +26,7 @@ use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, Body, Promoted};
+use rustc_middle::thir;
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
 use rustc_serialize::{opaque, Decodable, Decoder};
@@ -540,7 +541,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
     }
 }
 
-impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
     fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
         ty::codec::RefDecodable::decode(d)
     }
@@ -1198,14 +1199,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .decode((self, tcx))
     }
 
-    fn get_mir_abstract_const(
+    fn get_thir_abstract_const(
         &self,
         tcx: TyCtxt<'tcx>,
         id: DefIndex,
-    ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
         self.root
             .tables
-            .mir_abstract_consts
+            .thir_abstract_consts
             .get(self, id)
             .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx)))))
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 41839c58021ab..1a147242619a7 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -117,7 +117,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
     mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) }
     promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
-    mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
+    thir_abstract_const => { cdata.get_thir_abstract_const(tcx, def_id.index) }
     unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
     const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) }
     mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index d8b9a4799760e..60d7f0f85bb57 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -23,6 +23,7 @@ use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
 };
 use rustc_middle::mir::interpret;
+use rustc_middle::thir;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
@@ -344,7 +345,7 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
     fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
         (**self).encode(s)
     }
@@ -1304,9 +1305,10 @@ impl EncodeContext<'a, 'tcx> {
             if encode_const {
                 record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
 
-                let abstract_const = self.tcx.mir_abstract_const(def_id);
+                // FIXME this feels wrong to have in `encode_mir`
+                let abstract_const = self.tcx.thir_abstract_const(def_id);
                 if let Ok(Some(abstract_const)) = abstract_const {
-                    record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
+                    record!(self.tables.thir_abstract_consts[def_id.to_def_id()] <- abstract_const);
                 }
             }
             record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a487753f4628a..e59e9ad5d15d6 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -15,6 +15,7 @@ use rustc_middle::hir::exports::Export;
 use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir;
+use rustc_middle::thir;
 use rustc_middle::ty::{self, ReprOptions, Ty};
 use rustc_serialize::opaque::Encoder;
 use rustc_session::config::SymbolManglingVersion;
@@ -305,7 +306,7 @@ define_tables! {
     mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
-    mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
+    thir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [thir::abstract_const::Node<'tcx>])>,
     const_defaults: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
     unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
     // `def_keys` and `def_path_hashes` represent a lazy version of a
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 38d4c5b4bd10e..ba8ccc71954ff 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -40,7 +40,6 @@ use self::graph_cyclic_cache::GraphIsCyclicCache;
 use self::predecessors::{PredecessorCache, Predecessors};
 pub use self::query::*;
 
-pub mod abstract_const;
 pub mod coverage;
 mod generic_graph;
 pub mod generic_graphviz;
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 1bdb6ca012b4a..a1c6a8bf99e79 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,6 +1,7 @@
 //! Values computed by queries that use MIR.
 
-use crate::mir::{abstract_const, Body, Promoted};
+use crate::mir::{Body, Promoted};
+use crate::thir::abstract_const;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::vec_map::VecMap;
@@ -433,14 +434,14 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     #[inline]
-    pub fn mir_abstract_const_opt_const_arg(
+    pub fn thir_abstract_const_opt_const_arg(
         self,
         def: ty::WithOptConstParam<DefId>,
     ) -> Result<Option<&'tcx [abstract_const::Node<'tcx>]>, ErrorReported> {
         if let Some((did, param_did)) = def.as_const_arg() {
-            self.mir_abstract_const_of_const_arg((did, param_did))
+            self.thir_abstract_const_of_const_arg((did, param_did))
         } else {
-            self.mir_abstract_const(def.did)
+            self.thir_abstract_const(def.did)
         }
     }
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c93996162e3e3..19535195488b7 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -295,17 +295,17 @@ rustc_queries! {
     }
 
     /// Try to build an abstract representation of the given constant.
-    query mir_abstract_const(
+    query thir_abstract_const(
         key: DefId
-    ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
         desc {
             |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
         }
     }
     /// Try to build an abstract representation of the given constant.
-    query mir_abstract_const_of_const_arg(
+    query thir_abstract_const_of_const_arg(
         key: (LocalDefId, DefId)
-    ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
         desc {
             |tcx|
             "building an abstract representation for the const argument {}",
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 3012676c872bd..8d6fd1e729d3b 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -33,6 +33,9 @@ use rustc_target::asm::InlineAsmRegOrRegClass;
 use std::fmt;
 use std::ops::Index;
 
+pub mod abstract_const;
+pub mod visit;
+
 newtype_index! {
     /// An index to an [`Arm`] stored in [`Thir::arms`]
     #[derive(HashStable)]
@@ -818,246 +821,3 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
         }
     }
 }
-
-pub mod visit {
-    use super::*;
-    pub trait Visitor<'a, 'tcx: 'a>: Sized {
-        fn thir(&self) -> &'a Thir<'tcx>;
-
-        fn visit_expr(&mut self, expr: &Expr<'tcx>) {
-            walk_expr(self, expr);
-        }
-
-        fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
-            walk_stmt(self, stmt);
-        }
-
-        fn visit_block(&mut self, block: &Block) {
-            walk_block(self, block);
-        }
-
-        fn visit_arm(&mut self, arm: &Arm<'tcx>) {
-            walk_arm(self, arm);
-        }
-
-        fn visit_pat(&mut self, pat: &Pat<'tcx>) {
-            walk_pat(self, pat);
-        }
-
-        fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
-    }
-
-    pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
-        use ExprKind::*;
-        match expr.kind {
-            Scope { value, region_scope: _, lint_level: _ } => {
-                visitor.visit_expr(&visitor.thir()[value])
-            }
-            Box { value } => visitor.visit_expr(&visitor.thir()[value]),
-            If { cond, then, else_opt, if_then_scope: _ } => {
-                visitor.visit_expr(&visitor.thir()[cond]);
-                visitor.visit_expr(&visitor.thir()[then]);
-                if let Some(else_expr) = else_opt {
-                    visitor.visit_expr(&visitor.thir()[else_expr]);
-                }
-            }
-            Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
-                visitor.visit_expr(&visitor.thir()[fun]);
-                for &arg in &**args {
-                    visitor.visit_expr(&visitor.thir()[arg]);
-                }
-            }
-            Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
-            Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
-                visitor.visit_expr(&visitor.thir()[lhs]);
-                visitor.visit_expr(&visitor.thir()[rhs]);
-            }
-            Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
-            Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
-            Use { source } => visitor.visit_expr(&visitor.thir()[source]),
-            NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
-            Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
-            Let { expr, .. } => {
-                visitor.visit_expr(&visitor.thir()[expr]);
-            }
-            Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
-            Match { scrutinee, ref arms } => {
-                visitor.visit_expr(&visitor.thir()[scrutinee]);
-                for &arm in &**arms {
-                    visitor.visit_arm(&visitor.thir()[arm]);
-                }
-            }
-            Block { ref body } => visitor.visit_block(body),
-            Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
-                visitor.visit_expr(&visitor.thir()[lhs]);
-                visitor.visit_expr(&visitor.thir()[rhs]);
-            }
-            Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
-            Index { lhs, index } => {
-                visitor.visit_expr(&visitor.thir()[lhs]);
-                visitor.visit_expr(&visitor.thir()[index]);
-            }
-            VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
-            Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]),
-            AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
-            Break { value, label: _ } => {
-                if let Some(value) = value {
-                    visitor.visit_expr(&visitor.thir()[value])
-                }
-            }
-            Continue { label: _ } => {}
-            Return { value } => {
-                if let Some(value) = value {
-                    visitor.visit_expr(&visitor.thir()[value])
-                }
-            }
-            ConstBlock { value } => visitor.visit_const(value),
-            Repeat { value, count } => {
-                visitor.visit_expr(&visitor.thir()[value]);
-                visitor.visit_const(count);
-            }
-            Array { ref fields } | Tuple { ref fields } => {
-                for &field in &**fields {
-                    visitor.visit_expr(&visitor.thir()[field]);
-                }
-            }
-            Adt(box crate::thir::Adt {
-                ref fields,
-                ref base,
-                adt_def: _,
-                variant_index: _,
-                substs: _,
-                user_ty: _,
-            }) => {
-                for field in &**fields {
-                    visitor.visit_expr(&visitor.thir()[field.expr]);
-                }
-                if let Some(base) = base {
-                    visitor.visit_expr(&visitor.thir()[base.base]);
-                }
-            }
-            PlaceTypeAscription { source, user_ty: _ }
-            | ValueTypeAscription { source, user_ty: _ } => {
-                visitor.visit_expr(&visitor.thir()[source])
-            }
-            Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
-            Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
-            StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
-            InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
-                for op in &**operands {
-                    use InlineAsmOperand::*;
-                    match op {
-                        In { expr, reg: _ }
-                        | Out { expr: Some(expr), reg: _, late: _ }
-                        | InOut { expr, reg: _, late: _ }
-                        | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]),
-                        SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
-                            visitor.visit_expr(&visitor.thir()[*in_expr]);
-                            if let Some(out_expr) = out_expr {
-                                visitor.visit_expr(&visitor.thir()[*out_expr]);
-                            }
-                        }
-                        Out { expr: None, reg: _, late: _ }
-                        | Const { value: _, span: _ }
-                        | SymStatic { def_id: _ } => {}
-                    }
-                }
-            }
-            ThreadLocalRef(_) => {}
-            LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
-                for &out_expr in &**outputs {
-                    visitor.visit_expr(&visitor.thir()[out_expr]);
-                }
-                for &in_expr in &**inputs {
-                    visitor.visit_expr(&visitor.thir()[in_expr]);
-                }
-            }
-            Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
-        }
-    }
-
-    pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
-        match &stmt.kind {
-            StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
-            StmtKind::Let {
-                initializer,
-                remainder_scope: _,
-                init_scope: _,
-                ref pattern,
-                lint_level: _,
-            } => {
-                if let Some(init) = initializer {
-                    visitor.visit_expr(&visitor.thir()[*init]);
-                }
-                visitor.visit_pat(pattern);
-            }
-        }
-    }
-
-    pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) {
-        for &stmt in &*block.stmts {
-            visitor.visit_stmt(&visitor.thir()[stmt]);
-        }
-        if let Some(expr) = block.expr {
-            visitor.visit_expr(&visitor.thir()[expr]);
-        }
-    }
-
-    pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) {
-        match arm.guard {
-            Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]),
-            Some(Guard::IfLet(ref pat, expr)) => {
-                visitor.visit_pat(pat);
-                visitor.visit_expr(&visitor.thir()[expr]);
-            }
-            None => {}
-        }
-        visitor.visit_pat(&arm.pattern);
-        visitor.visit_expr(&visitor.thir()[arm.body]);
-    }
-
-    pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) {
-        use PatKind::*;
-        match pat.kind.as_ref() {
-            AscribeUserType { subpattern, ascription: _ }
-            | Deref { subpattern }
-            | Binding {
-                subpattern: Some(subpattern),
-                mutability: _,
-                mode: _,
-                var: _,
-                ty: _,
-                is_primary: _,
-                name: _,
-            } => visitor.visit_pat(&subpattern),
-            Binding { .. } | Wild => {}
-            Variant { subpatterns, adt_def: _, substs: _, variant_index: _ }
-            | Leaf { subpatterns } => {
-                for subpattern in subpatterns {
-                    visitor.visit_pat(&subpattern.pattern);
-                }
-            }
-            Constant { value } => visitor.visit_const(value),
-            Range(range) => {
-                visitor.visit_const(range.lo);
-                visitor.visit_const(range.hi);
-            }
-            Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
-                for subpattern in prefix {
-                    visitor.visit_pat(&subpattern);
-                }
-                if let Some(pat) = slice {
-                    visitor.visit_pat(pat);
-                }
-                for subpattern in suffix {
-                    visitor.visit_pat(&subpattern);
-                }
-            }
-            Or { pats } => {
-                for pat in pats {
-                    visitor.visit_pat(&pat);
-                }
-            }
-        };
-    }
-}
diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs
similarity index 100%
rename from compiler/rustc_middle/src/mir/abstract_const.rs
rename to compiler/rustc_middle/src/thir/abstract_const.rs
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
new file mode 100644
index 0000000000000..21826ac89d3a9
--- /dev/null
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -0,0 +1,238 @@
+use super::*;
+pub trait Visitor<'a, 'tcx: 'a>: Sized {
+    fn thir(&self) -> &'a Thir<'tcx>;
+
+    fn visit_expr(&mut self, expr: &Expr<'tcx>) {
+        walk_expr(self, expr);
+    }
+
+    fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
+        walk_stmt(self, stmt);
+    }
+
+    fn visit_block(&mut self, block: &Block) {
+        walk_block(self, block);
+    }
+
+    fn visit_arm(&mut self, arm: &Arm<'tcx>) {
+        walk_arm(self, arm);
+    }
+
+    fn visit_pat(&mut self, pat: &Pat<'tcx>) {
+        walk_pat(self, pat);
+    }
+
+    fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
+}
+
+pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
+    use ExprKind::*;
+    match expr.kind {
+        Scope { value, region_scope: _, lint_level: _ } => {
+            visitor.visit_expr(&visitor.thir()[value])
+        }
+        Box { value } => visitor.visit_expr(&visitor.thir()[value]),
+        If { cond, then, else_opt, if_then_scope: _ } => {
+            visitor.visit_expr(&visitor.thir()[cond]);
+            visitor.visit_expr(&visitor.thir()[then]);
+            if let Some(else_expr) = else_opt {
+                visitor.visit_expr(&visitor.thir()[else_expr]);
+            }
+        }
+        Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
+            visitor.visit_expr(&visitor.thir()[fun]);
+            for &arg in &**args {
+                visitor.visit_expr(&visitor.thir()[arg]);
+            }
+        }
+        Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
+        Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
+            visitor.visit_expr(&visitor.thir()[lhs]);
+            visitor.visit_expr(&visitor.thir()[rhs]);
+        }
+        Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+        Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
+        Use { source } => visitor.visit_expr(&visitor.thir()[source]),
+        NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
+        Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
+        Let { expr, .. } => {
+            visitor.visit_expr(&visitor.thir()[expr]);
+        }
+        Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
+        Match { scrutinee, ref arms } => {
+            visitor.visit_expr(&visitor.thir()[scrutinee]);
+            for &arm in &**arms {
+                visitor.visit_arm(&visitor.thir()[arm]);
+            }
+        }
+        Block { ref body } => visitor.visit_block(body),
+        Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
+            visitor.visit_expr(&visitor.thir()[lhs]);
+            visitor.visit_expr(&visitor.thir()[rhs]);
+        }
+        Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
+        Index { lhs, index } => {
+            visitor.visit_expr(&visitor.thir()[lhs]);
+            visitor.visit_expr(&visitor.thir()[index]);
+        }
+        VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
+        Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+        AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+        Break { value, label: _ } => {
+            if let Some(value) = value {
+                visitor.visit_expr(&visitor.thir()[value])
+            }
+        }
+        Continue { label: _ } => {}
+        Return { value } => {
+            if let Some(value) = value {
+                visitor.visit_expr(&visitor.thir()[value])
+            }
+        }
+        ConstBlock { value } => visitor.visit_const(value),
+        Repeat { value, count } => {
+            visitor.visit_expr(&visitor.thir()[value]);
+            visitor.visit_const(count);
+        }
+        Array { ref fields } | Tuple { ref fields } => {
+            for &field in &**fields {
+                visitor.visit_expr(&visitor.thir()[field]);
+            }
+        }
+        Adt(box crate::thir::Adt {
+            ref fields,
+            ref base,
+            adt_def: _,
+            variant_index: _,
+            substs: _,
+            user_ty: _,
+        }) => {
+            for field in &**fields {
+                visitor.visit_expr(&visitor.thir()[field.expr]);
+            }
+            if let Some(base) = base {
+                visitor.visit_expr(&visitor.thir()[base.base]);
+            }
+        }
+        PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => {
+            visitor.visit_expr(&visitor.thir()[source])
+        }
+        Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
+        Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
+        StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
+        InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
+            for op in &**operands {
+                use InlineAsmOperand::*;
+                match op {
+                    In { expr, reg: _ }
+                    | Out { expr: Some(expr), reg: _, late: _ }
+                    | InOut { expr, reg: _, late: _ }
+                    | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]),
+                    SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
+                        visitor.visit_expr(&visitor.thir()[*in_expr]);
+                        if let Some(out_expr) = out_expr {
+                            visitor.visit_expr(&visitor.thir()[*out_expr]);
+                        }
+                    }
+                    Out { expr: None, reg: _, late: _ }
+                    | Const { value: _, span: _ }
+                    | SymStatic { def_id: _ } => {}
+                }
+            }
+        }
+        ThreadLocalRef(_) => {}
+        LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
+            for &out_expr in &**outputs {
+                visitor.visit_expr(&visitor.thir()[out_expr]);
+            }
+            for &in_expr in &**inputs {
+                visitor.visit_expr(&visitor.thir()[in_expr]);
+            }
+        }
+        Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
+    }
+}
+
+pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
+    match &stmt.kind {
+        StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
+        StmtKind::Let {
+            initializer,
+            remainder_scope: _,
+            init_scope: _,
+            ref pattern,
+            lint_level: _,
+        } => {
+            if let Some(init) = initializer {
+                visitor.visit_expr(&visitor.thir()[*init]);
+            }
+            visitor.visit_pat(pattern);
+        }
+    }
+}
+
+pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) {
+    for &stmt in &*block.stmts {
+        visitor.visit_stmt(&visitor.thir()[stmt]);
+    }
+    if let Some(expr) = block.expr {
+        visitor.visit_expr(&visitor.thir()[expr]);
+    }
+}
+
+pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) {
+    match arm.guard {
+        Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]),
+        Some(Guard::IfLet(ref pat, expr)) => {
+            visitor.visit_pat(pat);
+            visitor.visit_expr(&visitor.thir()[expr]);
+        }
+        None => {}
+    }
+    visitor.visit_pat(&arm.pattern);
+    visitor.visit_expr(&visitor.thir()[arm.body]);
+}
+
+pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) {
+    use PatKind::*;
+    match pat.kind.as_ref() {
+        AscribeUserType { subpattern, ascription: _ }
+        | Deref { subpattern }
+        | Binding {
+            subpattern: Some(subpattern),
+            mutability: _,
+            mode: _,
+            var: _,
+            ty: _,
+            is_primary: _,
+            name: _,
+        } => visitor.visit_pat(&subpattern),
+        Binding { .. } | Wild => {}
+        Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } | Leaf { subpatterns } => {
+            for subpattern in subpatterns {
+                visitor.visit_pat(&subpattern.pattern);
+            }
+        }
+        Constant { value } => visitor.visit_const(value),
+        Range(range) => {
+            visitor.visit_const(range.lo);
+            visitor.visit_const(range.hi);
+        }
+        Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
+            for subpattern in prefix {
+                visitor.visit_pat(&subpattern);
+            }
+            if let Some(pat) = slice {
+                visitor.visit_pat(pat);
+            }
+            for subpattern in suffix {
+                visitor.visit_pat(&subpattern);
+            }
+        }
+        Or { pats } => {
+            for pat in pats {
+                visitor.visit_pat(&pat);
+            }
+        }
+    };
+}
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 74edb17fe32f1..e21a2d1034cdd 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -9,7 +9,7 @@ pub mod specialization_graph;
 mod structural_impls;
 
 use crate::infer::canonical::Canonical;
-use crate::mir::abstract_const::NotConstEvaluatable;
+use crate::thir::abstract_const::NotConstEvaluatable;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, AdtKind, Ty, TyCtxt};
 
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 4edb6a327b035..8b70692960df9 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -12,6 +12,7 @@ use crate::mir::{
     self,
     interpret::{AllocId, Allocation},
 };
+use crate::thir;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, List, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
@@ -362,7 +363,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>,
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] {
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] {
     fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
         Ok(decoder.tcx().arena.alloc_from_iter(
             (0..decoder.read_usize()?)
@@ -372,7 +373,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::N
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] {
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] {
     fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
         Ok(decoder.tcx().arena.alloc_from_iter(
             (0..decoder.read_usize()?)
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index e931c686dde59..0ee740a646359 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -48,11 +48,11 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
     match def {
         ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => {
             tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did));
-            tcx.ensure().mir_abstract_const_of_const_arg((did, const_param_did));
+            tcx.ensure().thir_abstract_const_of_const_arg((did, const_param_did));
         }
         ty::WithOptConstParam { did, const_param_did: None } => {
             tcx.ensure().thir_check_unsafety(did);
-            tcx.ensure().mir_abstract_const(did);
+            tcx.ensure().thir_abstract_const(did);
         }
     }
 
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 22abce65a4b7d..20232e635a2b8 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -307,7 +307,6 @@ fn mir_promoted(
     // this point, before we steal the mir-const result.
     // Also this means promotion can rely on all const checks having been done.
     let _ = tcx.mir_const_qualif_opt_const_arg(def);
-    let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global());
     let mut body = tcx.mir_const(def).steal();
 
     let mut required_consts = Vec::new();
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 910249ecc479e..4dcb98ae7e960 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -19,8 +19,8 @@ use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
 use rustc_middle::bug;
 use rustc_middle::hir::map::Map;
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
-use rustc_middle::mir::abstract_const::Node as ACNode;
 use rustc_middle::span_bug;
+use rustc_middle::thir::abstract_const::Node as ACNode;
 use rustc_middle::ty::fold::TypeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 5c2803c67e73f..2903e220b3b07 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -9,6 +9,7 @@ use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, interpret};
+use rustc_middle::thir;
 use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_query_system::dep_graph::DepContext;
@@ -906,7 +907,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
     }
 }
 
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
         RefDecodable::decode(d)
     }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 4251dc5e93904..8c2a3d4abf41b 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -6,7 +6,7 @@
 //! this is not as easy.
 //!
 //! In this case we try to build an abstract representation of this constant using
-//! `mir_abstract_const` which can then be checked for structural equality with other
+//! `thir_abstract_const` which can then be checked for structural equality with other
 //! generic constants mentioned in the `caller_bounds` of the current environment.
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::ErrorReported;
@@ -14,9 +14,9 @@ use rustc_hir::def::DefKind;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir;
-use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir;
+use rustc_middle::thir::abstract_const::{Node, NodeId, NotConstEvaluatable};
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_session::lint;
@@ -197,7 +197,7 @@ impl<'tcx> AbstractConst<'tcx> {
         tcx: TyCtxt<'tcx>,
         uv: ty::Unevaluated<'tcx, ()>,
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
-        let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?;
+        let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
         debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
         Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) }))
     }
@@ -421,10 +421,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
 }
 
 /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
-pub(super) fn mir_abstract_const<'tcx>(
+pub(super) fn thir_abstract_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
-) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
     if tcx.features().generic_const_exprs {
         match tcx.def_kind(def.did) {
             // FIXME(generic_const_exprs): We currently only do this for anonymous constants,
@@ -435,7 +435,7 @@ pub(super) fn mir_abstract_const<'tcx>(
             DefKind::AnonConst => (),
             _ => return Ok(None),
         }
-        
+
         let body = tcx.thir_body(def);
         if body.0.borrow().exprs.is_empty() {
             // type error in constant, there is no thir
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 9ce6c58a0f1df..4d3a8324d7987 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -19,7 +19,7 @@ use rustc_hir::intravisit::Visitor;
 use rustc_hir::GenericParam;
 use rustc_hir::Item;
 use rustc_hir::Node;
-use rustc_middle::mir::abstract_const::NotConstEvaluatable;
+use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 18abcc72bcee8..b376f42929249 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -5,8 +5,8 @@ use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProce
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
-use rustc_middle::mir::abstract_const::NotConstEvaluatable;
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 44c675243838a..ef208c44471cb 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -827,16 +827,16 @@ pub fn provide(providers: &mut ty::query::Providers) {
         vtable_entries,
         vtable_trait_upcasting_coercion_new_vptr_slot,
         subst_and_check_impossible_predicates,
-        mir_abstract_const: |tcx, def_id| {
+        thir_abstract_const: |tcx, def_id| {
             let def_id = def_id.expect_local();
             if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
-                tcx.mir_abstract_const_of_const_arg(def)
+                tcx.thir_abstract_const_of_const_arg(def)
             } else {
-                const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
+                const_evaluatable::thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
             }
         },
-        mir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
-            const_evaluatable::mir_abstract_const(
+        thir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
+            const_evaluatable::thir_abstract_const(
                 tcx,
                 ty::WithOptConstParam { did, const_param_did: Some(param_did) },
             )
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 63bd10994b1ac..e001bb7445e8c 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -836,7 +836,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
             //
             // This shouldn't really matter though as we can't really use any
             // constants which are not considered const evaluatable.
-            use rustc_middle::mir::abstract_const::Node;
+            use rustc_middle::thir::abstract_const::Node;
             if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
                 const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
                     Node::Leaf(leaf) => {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 22013fb79cf79..01a38ffa7d0b2 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -34,8 +34,8 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
-use rustc_middle::mir::abstract_const::NotConstEvaluatable;
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::fast_reject;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;

From 79be0802557089b408776ba161d95f8f4b5d0683 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 03:02:12 +0100
Subject: [PATCH 12/18] remove comment

---
 compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 8c2a3d4abf41b..1aaed7cade281 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -385,7 +385,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             | ExprKind::Repeat { .. }
             | ExprKind::Array { .. }
             | ExprKind::Block { .. }
-            | ExprKind::NeverToAny { .. } // I dont think we can get this without adt construction
+            | ExprKind::NeverToAny { .. }
             | ExprKind::Tuple { .. }
             | ExprKind::Index { .. }
             | ExprKind::Field { .. }

From 955e2b2da0ca29042206a56060baa820a2d961e7 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 12:05:11 +0100
Subject: [PATCH 13/18] nits

---
 compiler/rustc_middle/src/mir/query.rs        | 13 -------
 .../rustc_middle/src/thir/abstract_const.rs   | 23 +++++++++--
 compiler/rustc_middle/src/thir/visit.rs       |  6 ++-
 .../src/traits/const_evaluatable.rs           | 39 +++++++++----------
 4 files changed, 43 insertions(+), 38 deletions(-)

diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index a1c6a8bf99e79..567f65e83d98c 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,7 +1,6 @@
 //! Values computed by queries that use MIR.
 
 use crate::mir::{Body, Promoted};
-use crate::thir::abstract_const;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::vec_map::VecMap;
@@ -432,16 +431,4 @@ impl<'tcx> TyCtxt<'tcx> {
             self.mir_for_ctfe(def.did)
         }
     }
-
-    #[inline]
-    pub fn thir_abstract_const_opt_const_arg(
-        self,
-        def: ty::WithOptConstParam<DefId>,
-    ) -> Result<Option<&'tcx [abstract_const::Node<'tcx>]>, ErrorReported> {
-        if let Some((did, param_did)) = def.as_const_arg() {
-            self.thir_abstract_const_of_const_arg((did, param_did))
-        } else {
-            self.thir_abstract_const(def.did)
-        }
-    }
 }
diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs
index 27849e4bdb0bf..00f1390eb4d4e 100644
--- a/compiler/rustc_middle/src/thir/abstract_const.rs
+++ b/compiler/rustc_middle/src/thir/abstract_const.rs
@@ -1,6 +1,7 @@
 //! A subset of a mir body used for const evaluatability checking.
 use crate::mir;
-use crate::ty::{self, Ty};
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_errors::ErrorReported;
 
 rustc_index::newtype_index! {
     /// An index into an `AbstractConst`.
@@ -22,13 +23,13 @@ pub enum Node<'tcx> {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 pub enum NotConstEvaluatable {
-    Error(rustc_errors::ErrorReported),
+    Error(ErrorReported),
     MentionsInfer,
     MentionsParam,
 }
 
-impl From<rustc_errors::ErrorReported> for NotConstEvaluatable {
-    fn from(e: rustc_errors::ErrorReported) -> NotConstEvaluatable {
+impl From<ErrorReported> for NotConstEvaluatable {
+    fn from(e: ErrorReported) -> NotConstEvaluatable {
         NotConstEvaluatable::Error(e)
     }
 }
@@ -36,3 +37,17 @@ impl From<rustc_errors::ErrorReported> for NotConstEvaluatable {
 TrivialTypeFoldableAndLiftImpls! {
     NotConstEvaluatable,
 }
+
+impl<'tcx> TyCtxt<'tcx> {
+    #[inline]
+    pub fn thir_abstract_const_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<rustc_hir::def_id::DefId>,
+    ) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorReported> {
+        if let Some((did, param_did)) = def.as_const_arg() {
+            self.thir_abstract_const_of_const_arg((did, param_did))
+        } else {
+            self.thir_abstract_const(def.did)
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 21826ac89d3a9..7fc15e02fcd30 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -1,4 +1,8 @@
-use super::*;
+use super::{
+    Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir,
+};
+use rustc_middle::ty::Const;
+
 pub trait Visitor<'a, 'tcx: 'a>: Sized {
     fn thir(&self) -> &'a Thir<'tcx>;
 
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 1aaed7cade281..1845b9d1314b1 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -8,7 +8,6 @@
 //! In this case we try to build an abstract representation of this constant using
 //! `thir_abstract_const` which can then be checked for structural equality with other
 //! generic constants mentioned in the `caller_bounds` of the current environment.
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::ErrorReported;
 use rustc_hir::def::DefKind;
 use rustc_index::vec::IndexVec;
@@ -227,8 +226,7 @@ impl<'tcx> AbstractConst<'tcx> {
 struct AbstractConstBuilder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body_id: thir::ExprId,
-    /// `Lrc` is used to avoid borrowck difficulties in `recurse_build`
-    body: Lrc<&'a thir::Thir<'tcx>>,
+    body: &'a thir::Thir<'tcx>,
     /// The current WIP node tree.
     nodes: IndexVec<NodeId, Node<'tcx>>,
 }
@@ -253,8 +251,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
         (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId),
     ) -> Result<Option<AbstractConstBuilder<'a, 'tcx>>, ErrorReported> {
-        let builder =
-            AbstractConstBuilder { tcx, body_id, body: Lrc::new(body), nodes: IndexVec::new() };
+        let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() };
 
         struct IsThirPolymorphic<'a, 'tcx> {
             is_poly: bool,
@@ -328,7 +325,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
 
     fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorReported> {
         use thir::ExprKind;
-        let node = &self.body.clone().exprs[node];
+        let node = &self.body.exprs[node];
         debug!("recurse_build: node={:?}", node);
         Ok(match &node.kind {
             // I dont know if handling of these 3 is correct
@@ -338,10 +335,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
 
             // subtle: associated consts are literals this arm handles
             // `<T as Trait>::ASSOC` as well as `12`
-            &ExprKind::Literal { literal, .. }
-            | &ExprKind::StaticRef { literal, .. } => self.nodes.push(Node::Leaf(literal)),
+            &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)),
 
-            // FIXME(generic_const_exprs) handle `from_hir_call` field
+            // FIXME(generic_const_exprs): Handle `from_hir_call` field
             ExprKind::Call { fun, args,  .. } => {
                 let fun = self.recurse_build(*fun)?;
 
@@ -361,7 +357,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 let arg = self.recurse_build(arg)?;
                 self.nodes.push(Node::UnaryOp(op, arg))
             },
-            // this is necessary so that the following compiles:
+            // This is necessary so that the following compiles:
             //
             // ```
             // fn foo<const N: usize>(a: [(); N + 1]) {
@@ -369,16 +365,16 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             // }
             // ```
             ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?,
-            // ExprKind::Use happens when a `hir::ExprKind::Cast` is a
+            // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a
             // "coercion cast" i.e. using a coercion or is a no-op.
-            // this is important so that `N as usize as usize` doesnt unify with `N as usize`
+            // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested)
             &ExprKind::Use { source}
             | &ExprKind::Cast { source } => {
                 let arg = self.recurse_build(source)?;
                 self.nodes.push(Node::Cast(arg, node.ty))
             },
 
-            // FIXME(generic_const_exprs) we want to support these
+            // FIXME(generic_const_exprs): We may want to support these.
             ExprKind::AddressOf { .. }
             | ExprKind::Borrow { .. }
             | ExprKind::Deref { .. }
@@ -390,21 +386,24 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             | ExprKind::Index { .. }
             | ExprKind::Field { .. }
             | ExprKind::ConstBlock { .. }
-            | ExprKind::Adt(_) => return self.error(
+            | ExprKind::Adt(_) => self.error(
                     Some(node.span),
                     "unsupported operation in generic constant, this may be supported in the future",
-                ).map(|never| never),
+                )?,
 
             ExprKind::Match { .. }
-            | ExprKind::VarRef { .. } //
-            | ExprKind::UpvarRef { .. } // we dont permit let stmts so...
+            // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen
+            | ExprKind::VarRef { .. }
+            | ExprKind::UpvarRef { .. }
             | ExprKind::Closure { .. }
             | ExprKind::Let { .. } // let expressions imply control flow
             | ExprKind::Loop { .. }
             | ExprKind::Assign { .. }
+            | ExprKind::StaticRef { .. }
             | ExprKind::LogicalOp { .. }
-            | ExprKind::Unary { .. } //
-            | ExprKind::Binary { .. } // we handle valid unary/binary ops above
+            // we handle valid unary/binary ops above
+            | ExprKind::Unary { .. }
+            | ExprKind::Binary { .. }
             | ExprKind::Break { .. }
             | ExprKind::Continue { .. }
             | ExprKind::If { .. }
@@ -415,7 +414,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             | ExprKind::Box { .. } // allocations not allowed in constants
             | ExprKind::AssignOp { .. }
             | ExprKind::InlineAsm { .. }
-            | ExprKind::Yield { .. } => return self.error(Some(node.span), "unsupported operation in generic constant").map(|never| never),
+            | ExprKind::Yield { .. } => self.error(Some(node.span), "unsupported operation in generic constant")?,
         })
     }
 }

From 8c7954dc425e8c6ee4aaaf14be5015ad8982d540 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 13:24:04 +0100
Subject: [PATCH 14/18] add a `CastKind` to `Node::Cast`

---
 .../rustc_middle/src/thir/abstract_const.rs     | 10 +++++++++-
 compiler/rustc_privacy/src/lib.rs               |  2 +-
 .../src/traits/const_evaluatable.rs             | 17 ++++++++++-------
 .../src/traits/object_safety.rs                 |  2 +-
 .../abstract-consts-as-cast-5.rs                | 11 +++++++++++
 .../abstract-consts-as-cast-5.stderr            | 10 ++++++++++
 6 files changed, 42 insertions(+), 10 deletions(-)
 create mode 100644 src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs
 create mode 100644 src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr

diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs
index 00f1390eb4d4e..f80beadd6e551 100644
--- a/compiler/rustc_middle/src/thir/abstract_const.rs
+++ b/compiler/rustc_middle/src/thir/abstract_const.rs
@@ -11,6 +11,14 @@ rustc_index::newtype_index! {
     }
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum CastKind {
+    /// thir::ExprKind::As
+    As,
+    /// thir::ExprKind::Use
+    Use,
+}
+
 /// A node of an `AbstractConst`.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 pub enum Node<'tcx> {
@@ -18,7 +26,7 @@ pub enum Node<'tcx> {
     Binop(mir::BinOp, NodeId, NodeId),
     UnaryOp(mir::UnOp, NodeId),
     FunctionCall(NodeId, &'tcx [NodeId]),
-    Cast(NodeId, Ty<'tcx>),
+    Cast(CastKind, NodeId, Ty<'tcx>),
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 4dcb98ae7e960..391e43054239d 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -158,7 +158,7 @@ where
                 let leaf = leaf.subst(tcx, ct.substs);
                 self.visit_const(leaf)
             }
-            ACNode::Cast(_, ty) => self.visit_ty(ty),
+            ACNode::Cast(_, _, ty) => self.visit_ty(ty),
             ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
                 ControlFlow::CONTINUE
             }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 1845b9d1314b1..26c71a0f53921 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -15,7 +15,7 @@ use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir;
-use rustc_middle::thir::abstract_const::{Node, NodeId, NotConstEvaluatable};
+use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable};
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_session::lint;
@@ -91,7 +91,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
 
                         ControlFlow::CONTINUE
                     }
-                    Node::Cast(_, ty) => {
+                    Node::Cast(_, _, ty) => {
                         let ty = ty.subst(tcx, ct.substs);
                         if ty.has_infer_types_or_consts() {
                             failure_kind = FailureKind::MentionsInfer;
@@ -368,10 +368,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a
             // "coercion cast" i.e. using a coercion or is a no-op.
             // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested)
-            &ExprKind::Use { source}
-            | &ExprKind::Cast { source } => {
+            &ExprKind::Use { source } => {
                 let arg = self.recurse_build(source)?;
-                self.nodes.push(Node::Cast(arg, node.ty))
+                self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty))
+            },
+            &ExprKind::Cast { source } => {
+                let arg = self.recurse_build(source)?;
+                self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty))
             },
 
             // FIXME(generic_const_exprs): We may want to support these.
@@ -494,7 +497,7 @@ where
                 recurse(tcx, ct.subtree(func), f)?;
                 args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
             }
-            Node::Cast(operand, _) => recurse(tcx, ct.subtree(operand), f),
+            Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
         }
     }
 
@@ -577,7 +580,7 @@ pub(super) fn try_unify<'tcx>(
                 && iter::zip(a_args, b_args)
                     .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
         }
-        (Node::Cast(a_operand, a_ty), Node::Cast(b_operand, b_ty)) if (a_ty == b_ty) => {
+        (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) if (a_ty == b_ty) && (a_kind == b_kind) => {
             try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
         }
         // use this over `_ => false` to make adding variants to `Node` less error prone
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index e001bb7445e8c..70cdbe4d5c7cb 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -843,7 +843,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
                         let leaf = leaf.subst(self.tcx, ct.substs);
                         self.visit_const(leaf)
                     }
-                    Node::Cast(_, ty) => self.visit_ty(ty),
+                    Node::Cast(_, _, ty) => self.visit_ty(ty),
                     Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
                         ControlFlow::CONTINUE
                     }
diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs
new file mode 100644
index 0000000000000..b3cde61f5e7f2
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs
@@ -0,0 +1,11 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: u8>(a: [(); N as usize]) {
+    bar::<{ N as usize as usize }>();
+    //~^ error: unconstrained generic constant
+}
+
+fn bar<const N: usize>() {}
+
+fn main() {}
\ No newline at end of file
diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr
new file mode 100644
index 0000000000000..d48b639dbdee3
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr
@@ -0,0 +1,10 @@
+error: unconstrained generic constant
+  --> $DIR/abstract-consts-as-cast-5.rs:5:11
+   |
+LL |     bar::<{ N as usize as usize }>();
+   |           ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { N as usize as usize }]:`
+
+error: aborting due to previous error
+

From 3212734bd744719dc197a19902d083c591670ab1 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 13:36:50 +0100
Subject: [PATCH 15/18] resolve `from_hir_call` FIXME

---
 .../src/traits/const_evaluatable.rs           |  1 -
 .../abstract-consts-as-cast-5.rs              |  2 +-
 .../unify-op-with-fn-call.rs                  | 23 +++++++++++++++++++
 3 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs

diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 26c71a0f53921..702b5a508b744 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -337,7 +337,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             // `<T as Trait>::ASSOC` as well as `12`
             &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)),
 
-            // FIXME(generic_const_exprs): Handle `from_hir_call` field
             ExprKind::Call { fun, args,  .. } => {
                 let fun = self.recurse_build(*fun)?;
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs
index b3cde61f5e7f2..916d60c0e0def 100644
--- a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs
@@ -8,4 +8,4 @@ fn foo<const N: u8>(a: [(); N as usize]) {
 
 fn bar<const N: usize>() {}
 
-fn main() {}
\ No newline at end of file
+fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
new file mode 100644
index 0000000000000..abbeb2c928ed4
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
@@ -0,0 +1,23 @@
+#![feature(generic_const_exprs, adt_const_params, const_trait_impl)]
+#![allow(incomplete_features)]
+
+#[derive(PartialEq, Eq)]
+struct Foo(u8);
+
+impl const std::ops::Add for Foo {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        self
+    }
+}
+
+struct Evaluatable<const N: Foo>;
+
+fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
+    bar::<{ std::ops::Add::add(N, N) }>();
+}
+
+fn bar<const N: Foo>() {}
+
+fn main() {}

From cd2915eddb446df2d89922d3b68080d091dc247e Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 13:49:31 +0100
Subject: [PATCH 16/18] fmt

---
 .../rustc_trait_selection/src/traits/const_evaluatable.rs     | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 702b5a508b744..4f178f777afb2 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -579,7 +579,9 @@ pub(super) fn try_unify<'tcx>(
                 && iter::zip(a_args, b_args)
                     .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
         }
-        (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) if (a_ty == b_ty) && (a_kind == b_kind) => {
+        (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
+            if (a_ty == b_ty) && (a_kind == b_kind) =>
+        {
             try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
         }
         // use this over `_ => false` to make adding variants to `Node` less error prone

From fd9bb30ab8fc65da735272f9cfd55d1368da9069 Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Tue, 7 Sep 2021 14:27:07 +0100
Subject: [PATCH 17/18] CI please

---
 .../const-generics/generic_const_exprs/unify-op-with-fn-call.rs  | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
index abbeb2c928ed4..bb054bec6b6c2 100644
--- a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
@@ -1,3 +1,4 @@
+// check-pass
 #![feature(generic_const_exprs, adt_const_params, const_trait_impl)]
 #![allow(incomplete_features)]
 

From 8295e4a6cfb12ce74c480172c2854f76d1428b8b Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Thu, 9 Sep 2021 15:43:59 +0100
Subject: [PATCH 18/18] add test for builtin types N + N unifying with fn call

---
 compiler/rustc_metadata/src/rmeta/encoder.rs        |  2 +-
 .../src/traits/const_evaluatable.rs                 | 13 ++++++++++---
 .../generic_const_exprs/unify-op-with-fn-call.rs    | 13 ++++++++++++-
 .../unify-op-with-fn-call.stderr                    | 10 ++++++++++
 4 files changed, 33 insertions(+), 5 deletions(-)
 create mode 100644 src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr

diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 60d7f0f85bb57..97c0bca5d911c 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1305,7 +1305,7 @@ impl EncodeContext<'a, 'tcx> {
             if encode_const {
                 record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
 
-                // FIXME this feels wrong to have in `encode_mir`
+                // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir`
                 let abstract_const = self.tcx.thir_abstract_const(def_id);
                 if let Ok(Some(abstract_const)) = abstract_const {
                     record!(self.tables.thir_abstract_consts[def_id.to_def_id()] <- abstract_const);
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 4f178f777afb2..24fa5007f1ecd 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -267,10 +267,16 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
 
             fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) {
                 self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx);
-                if self.is_poly {
-                    return;
+                if self.is_poly == false {
+                    visit::walk_expr(self, expr)
+                }
+            }
+
+            fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) {
+                self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx);
+                if self.is_poly == false {
+                    visit::walk_pat(self, pat);
                 }
-                visit::walk_expr(self, expr);
             }
 
             fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) {
@@ -280,6 +286,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
 
         let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx };
         visit::walk_expr(&mut is_poly_vis, &body[body_id]);
+        debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly);
         if is_poly_vis.is_poly == false {
             return Ok(None);
         }
diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
index bb054bec6b6c2..c0404d35b0887 100644
--- a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
@@ -1,7 +1,7 @@
-// check-pass
 #![feature(generic_const_exprs, adt_const_params, const_trait_impl)]
 #![allow(incomplete_features)]
 
+// test `N + N` unifies with explicit function calls for non-builtin-types
 #[derive(PartialEq, Eq)]
 struct Foo(u8);
 
@@ -21,4 +21,15 @@ fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
 
 fn bar<const N: Foo>() {}
 
+// test that `N + N` unifies with explicit function calls for builin-types
+struct Evaluatable2<const N: usize>;
+
+fn foo2<const N: usize>(a: Evaluatable2<{ N + N }>) {
+    bar2::<{ std::ops::Add::add(N, N) }>();
+    //~^ error: unconstrained generic constant
+    // FIXME(generic_const_exprs) make this not an error
+}
+
+fn bar2<const N: usize>() {}
+
 fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
new file mode 100644
index 0000000000000..d18c7916f5f6f
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
@@ -0,0 +1,10 @@
+error: unconstrained generic constant
+  --> $DIR/unify-op-with-fn-call.rs:28:12
+   |
+LL |     bar2::<{ std::ops::Add::add(N, N) }>();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { std::ops::Add::add(N, N) }]:`
+
+error: aborting due to previous error
+