about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection')
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs (renamed from compiler/rustc_trait_selection/src/traits/codegen/mod.rs)5
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs145
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs231
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs97
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs35
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs50
12 files changed, 391 insertions, 273 deletions
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 406e8936e6e..42509cd8975 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -19,6 +19,7 @@
 #![feature(never_type)]
 #![feature(crate_visibility_modifier)]
 #![feature(or_patterns)]
+#![feature(control_flow_enum)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index ecaafee77e2..914fa1e52c2 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -15,6 +15,8 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config::nightly_options;
 use rustc_span::Span;
 
+use std::ops::ControlFlow;
+
 pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
 
 /// Information about the opaque types whose values we
@@ -691,26 +693,26 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
 where
     OP: FnMut(ty::Region<'tcx>),
 {
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ControlFlow<()> {
         t.as_ref().skip_binder().visit_with(self);
-        false // keep visiting
+        ControlFlow::CONTINUE
     }
 
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
         match *r {
             // ignore bound regions, keep visiting
-            ty::ReLateBound(_, _) => false,
+            ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
             _ => {
                 (self.op)(r);
-                false
+                ControlFlow::CONTINUE
             }
         }
     }
 
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
         // We're only interested in types involving regions
         if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
-            return false; // keep visiting
+            return ControlFlow::CONTINUE;
         }
 
         match ty.kind() {
@@ -745,7 +747,7 @@ where
             }
         }
 
-        false
+        ControlFlow::CONTINUE
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 05e6c4804ff..3cb6ec86261 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -121,7 +121,10 @@ where
     // contains unbound type parameters. It could be a slight
     // optimization to stop iterating early.
     if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
-        bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
+        infcx.tcx.sess.delay_span_bug(
+            rustc_span::DUMMY_SP,
+            &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),
+        );
     }
 
     let result = infcx.resolve_vars_if_possible(result);
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 1e1eb16faf4..638a8253e7e 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -24,6 +24,7 @@ use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::Span;
 
 use std::cmp;
+use std::ops::ControlFlow;
 
 /// Check if a given constant can be evaluated.
 pub fn is_const_evaluatable<'cx, 'tcx>(
@@ -85,8 +86,12 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
                         } else if leaf.has_param_types_or_consts() {
                             failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
                         }
+
+                        ControlFlow::CONTINUE
+                    }
+                    Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
+                        ControlFlow::CONTINUE
                     }
-                    Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => (),
                 });
 
                 match failure_kind {
@@ -194,12 +199,12 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
 ///
 /// This is only able to represent a subset of `MIR`,
 /// and should not leak any information about desugarings.
-#[derive(Clone, Copy)]
+#[derive(Debug, Clone, Copy)]
 pub struct AbstractConst<'tcx> {
     // FIXME: Consider adding something like `IndexSlice`
     // and use this here.
-    inner: &'tcx [Node<'tcx>],
-    substs: SubstsRef<'tcx>,
+    pub inner: &'tcx [Node<'tcx>],
+    pub substs: SubstsRef<'tcx>,
 }
 
 impl AbstractConst<'tcx> {
@@ -209,9 +214,21 @@ impl AbstractConst<'tcx> {
         substs: SubstsRef<'tcx>,
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
         let inner = tcx.mir_abstract_const_opt_const_arg(def)?;
+        debug!("AbstractConst::new({:?}) = {:?}", def, inner);
         Ok(inner.map(|inner| AbstractConst { inner, substs }))
     }
 
+    pub fn from_const(
+        tcx: TyCtxt<'tcx>,
+        ct: &ty::Const<'tcx>,
+    ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
+        match ct.val {
+            ty::ConstKind::Unevaluated(def, substs, None) => AbstractConst::new(tcx, def, substs),
+            ty::ConstKind::Error(_) => Err(ErrorReported),
+            _ => Ok(None),
+        }
+    }
+
     #[inline]
     pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
         AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs }
@@ -223,11 +240,23 @@ impl 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: &'a mir::Body<'tcx>,
     /// The current WIP node tree.
-    nodes: IndexVec<NodeId, Node<'tcx>>,
+    ///
+    /// 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>>,
     locals: IndexVec<mir::Local, NodeId>,
     /// We only allow field accesses if they access
     /// the result of a checked operation.
@@ -274,6 +303,27 @@ 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);
+            }
+        }
+
+        // Nodes start as unused.
+        self.nodes.push(WorkNode { node, span, used: false })
+    }
+
     fn place_to_local(
         &mut self,
         span: Span,
@@ -311,7 +361,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 let local = self.place_to_local(span, p)?;
                 Ok(self.locals[local])
             }
-            mir::Operand::Constant(ct) => Ok(self.nodes.push(Node::Leaf(ct.literal))),
+            mir::Operand::Constant(ct) => Ok(self.add_node(Node::Leaf(ct.literal), span)),
         }
     }
 
@@ -336,19 +386,19 @@ 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(stmt.source_info.span, place)?;
+                let local = self.place_to_local(span, place)?;
                 match *rvalue {
                     Rvalue::Use(ref operand) => {
-                        self.locals[local] =
-                            self.operand_to_node(stmt.source_info.span, operand)?;
+                        self.locals[local] = self.operand_to_node(span, operand)?;
                         Ok(())
                     }
                     Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
-                        let lhs = self.operand_to_node(stmt.source_info.span, lhs)?;
-                        let rhs = self.operand_to_node(stmt.source_info.span, rhs)?;
-                        self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs));
+                        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 {
@@ -356,18 +406,18 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                         }
                     }
                     Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
-                        let lhs = self.operand_to_node(stmt.source_info.span, lhs)?;
-                        let rhs = self.operand_to_node(stmt.source_info.span, rhs)?;
-                        self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs));
+                        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(stmt.source_info.span, operand)?;
-                        self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand));
+                        let operand = self.operand_to_node(span, operand)?;
+                        self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
                         Ok(())
                     }
-                    _ => self.error(Some(stmt.source_info.span), "unsupported rvalue")?,
+                    _ => self.error(Some(span), "unsupported rvalue")?,
                 }
             }
             // These are not actually relevant for us here, so we can ignore them.
@@ -415,13 +465,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                         .map(|arg| self.operand_to_node(terminator.source_info.span, arg))
                         .collect::<Result<Vec<NodeId>, _>>()?,
                 );
-                self.locals[local] = self.nodes.push(Node::FunctionCall(func, args));
+                self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span);
                 Ok(Some(target))
             }
-            // We only allow asserts for checked operations.
-            //
-            // These asserts seem to all have the form `!_local.0` so
-            // we only allow exactly that.
             TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
                 let p = match cond {
                     mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
@@ -430,7 +476,15 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
 
                 const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
                 debug!("proj: {:?}", p.projection);
-                if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
+                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));
@@ -457,7 +511,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             if let Some(next) = self.build_terminator(block.terminator())? {
                 block = &self.body.basic_blocks()[next];
             } else {
-                return Ok(self.tcx.arena.alloc_from_iter(self.nodes));
+                assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap());
+                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")?;
+                }
+
+                return Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node)));
             }
         }
     }
@@ -507,31 +567,36 @@ pub(super) fn try_unify_abstract_consts<'tcx>(
     // on `ErrorReported`.
 }
 
-fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F)
+pub fn walk_abstract_const<'tcx, F>(
+    tcx: TyCtxt<'tcx>,
+    ct: AbstractConst<'tcx>,
+    mut f: F,
+) -> ControlFlow<()>
 where
-    F: FnMut(Node<'tcx>),
+    F: FnMut(Node<'tcx>) -> ControlFlow<()>,
 {
-    recurse(tcx, ct, &mut f);
-    fn recurse<'tcx>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, f: &mut dyn FnMut(Node<'tcx>)) {
+    fn recurse<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        ct: AbstractConst<'tcx>,
+        f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<()>,
+    ) -> ControlFlow<()> {
         let root = ct.root();
-        f(root);
+        f(root)?;
         match root {
-            Node::Leaf(_) => (),
+            Node::Leaf(_) => ControlFlow::CONTINUE,
             Node::Binop(_, l, r) => {
-                recurse(tcx, ct.subtree(l), f);
-                recurse(tcx, ct.subtree(r), f);
-            }
-            Node::UnaryOp(_, v) => {
-                recurse(tcx, ct.subtree(v), f);
+                recurse(tcx, ct.subtree(l), f)?;
+                recurse(tcx, ct.subtree(r), f)
             }
+            Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f),
             Node::FunctionCall(func, args) => {
-                recurse(tcx, ct.subtree(func), f);
-                for &arg in args {
-                    recurse(tcx, ct.subtree(arg), f);
-                }
+                recurse(tcx, ct.subtree(func), f)?;
+                args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
             }
         }
     }
+
+    recurse(tcx, ct, &mut f)
 }
 
 /// Tries to unify two abstract constants using structural equality.
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 f53465266d2..f8bd3ab96e2 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1462,9 +1462,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
         let bound_predicate = predicate.bound_atom();
         let mut err = match bound_predicate.skip_binder() {
             ty::PredicateAtom::Trait(data, _) => {
-                let self_ty = data.trait_ref.self_ty();
                 let trait_ref = bound_predicate.rebind(data.trait_ref);
-                debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind(), trait_ref);
+                debug!("trait_ref {:?}", trait_ref);
 
                 if predicate.references_error() {
                     return;
@@ -1479,6 +1478,17 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 // known, since we don't dispatch based on region
                 // relationships.
 
+                // Pick the first substitution that still contains inference variables as the one
+                // we're going to emit an error for. If there are none (see above), fall back to
+                // the substitution for `Self`.
+                let subst = {
+                    let substs = data.trait_ref.substs;
+                    substs
+                        .iter()
+                        .find(|s| s.has_infer_types_or_consts())
+                        .unwrap_or_else(|| substs[0])
+                };
+
                 // This is kind of a hack: it frequently happens that some earlier
                 // error prevents types from being fully inferred, and then we get
                 // a bunch of uninteresting errors saying something like "<generic
@@ -1495,21 +1505,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 // check upstream for type errors and don't add the obligations to
                 // begin with in those cases.
                 if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
-                    self.emit_inference_failure_err(
-                        body_id,
-                        span,
-                        self_ty.into(),
-                        ErrorCode::E0282,
-                    )
-                    .emit();
+                    self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0282).emit();
                     return;
                 }
-                let mut err = self.emit_inference_failure_err(
-                    body_id,
-                    span,
-                    self_ty.into(),
-                    ErrorCode::E0283,
-                );
+                let mut err =
+                    self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283);
                 err.note(&format!("cannot satisfy `{}`", predicate));
                 if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
                     self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index efa9bd633ba..c0881befe24 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::{
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use std::fmt;
 
@@ -1845,9 +1845,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     err.note("all function arguments must have a statically known size");
                 }
                 if tcx.sess.opts.unstable_features.is_nightly_build()
-                    && !self.tcx.features().unsized_locals
+                    && !self.tcx.features().unsized_fn_params
                 {
-                    err.help("unsized locals are gated as an unstable feature");
+                    err.help("unsized fn params are gated as an unstable feature");
                 }
             }
             ObligationCauseCode::SizedReturnType => {
@@ -2114,10 +2114,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if self.predicate_may_hold(&try_obligation) && impls_future {
                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
                         if snippet.ends_with('?') {
-                            err.span_suggestion(
-                                span,
-                                "consider using `.await` here",
-                                format!("{}.await?", snippet.trim_end_matches('?')),
+                            err.span_suggestion_verbose(
+                                span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
+                                "consider `await`ing on the `Future`",
+                                ".await".to_string(),
                                 Applicability::MaybeIncorrect,
                             );
                         }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 495a250be7c..9a8b5534dfe 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,6 +1,6 @@
 use crate::infer::{InferCtxt, TyOrConstInferVar};
 use rustc_data_structures::obligation_forest::ProcessResult;
-use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
+use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
 use rustc_errors::ErrorReported;
 use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
@@ -129,13 +129,11 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
             debug!("select: starting another iteration");
 
             // Process pending obligations.
-            let outcome = self.predicates.process_obligations(
-                &mut FulfillProcessor {
+            let outcome: Outcome<_, _> =
+                self.predicates.process_obligations(&mut FulfillProcessor {
                     selcx,
                     register_region_obligations: self.register_region_obligations,
-                },
-                DoCompleted::No,
-            );
+                });
             debug!("select: outcome={:#?}", outcome);
 
             // FIXME: if we kept the original cache key, we could mark projection
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 0e43f1655dd..50efbbbe0fd 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -11,9 +11,10 @@
 use super::elaborate_predicates;
 
 use crate::infer::TyCtxtInferExt;
+use crate::traits::const_evaluatable::{self, AbstractConst};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{self, Obligation, ObligationCause};
-use rustc_errors::{Applicability, FatalError};
+use rustc_errors::FatalError;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
@@ -21,11 +22,12 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstnes
 use rustc_middle::ty::{Predicate, ToPredicate};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{MultiSpan, Span};
 use smallvec::SmallVec;
 
 use std::array;
 use std::iter;
+use std::ops::ControlFlow;
 
 pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation};
 
@@ -100,49 +102,7 @@ fn object_safety_violations_for_trait(
                 span,
             ) = violation
             {
-                // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
-                // It's also hard to get a use site span, so we use the method definition span.
-                tcx.struct_span_lint_hir(
-                    WHERE_CLAUSES_OBJECT_SAFETY,
-                    hir::CRATE_HIR_ID,
-                    *span,
-                    |lint| {
-                        let mut err = lint.build(&format!(
-                            "the trait `{}` cannot be made into an object",
-                            tcx.def_path_str(trait_def_id)
-                        ));
-                        let node = tcx.hir().get_if_local(trait_def_id);
-                        let msg = if let Some(hir::Node::Item(item)) = node {
-                            err.span_label(
-                                item.ident.span,
-                                "this trait cannot be made into an object...",
-                            );
-                            format!("...because {}", violation.error_msg())
-                        } else {
-                            format!(
-                                "the trait cannot be made into an object because {}",
-                                violation.error_msg()
-                            )
-                        };
-                        err.span_label(*span, &msg);
-                        match (node, violation.solution()) {
-                            (Some(_), Some((note, None))) => {
-                                err.help(&note);
-                            }
-                            (Some(_), Some((note, Some((sugg, span))))) => {
-                                err.span_suggestion(
-                                    span,
-                                    &note,
-                                    sugg,
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                            // Only provide the help if its a local trait, otherwise it's not actionable.
-                            _ => {}
-                        }
-                        err.emit();
-                    },
-                );
+                lint_object_unsafe_trait(tcx, *span, trait_def_id, violation);
                 false
             } else {
                 true
@@ -180,6 +140,51 @@ fn object_safety_violations_for_trait(
     violations
 }
 
+/// Lint object-unsafe trait.
+fn lint_object_unsafe_trait(
+    tcx: TyCtxt<'_>,
+    span: Span,
+    trait_def_id: DefId,
+    violation: &ObjectSafetyViolation,
+) {
+    // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
+    // It's also hard to get a use site span, so we use the method definition span.
+    tcx.struct_span_lint_hir(WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, |lint| {
+        let mut err = lint.build(&format!(
+            "the trait `{}` cannot be made into an object",
+            tcx.def_path_str(trait_def_id)
+        ));
+        let node = tcx.hir().get_if_local(trait_def_id);
+        let mut spans = MultiSpan::from_span(span);
+        if let Some(hir::Node::Item(item)) = node {
+            spans.push_span_label(
+                item.ident.span,
+                "this trait cannot be made into an object...".into(),
+            );
+            spans.push_span_label(span, format!("...because {}", violation.error_msg()));
+        } else {
+            spans.push_span_label(
+                span,
+                format!(
+                    "the trait cannot be made into an object because {}",
+                    violation.error_msg()
+                ),
+            );
+        };
+        err.span_note(
+            spans,
+            "for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
+             call to be resolvable dynamically; for more information visit \
+             <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
+        );
+        if node.is_some() {
+            // Only provide the help if its a local trait, otherwise it's not
+            violation.solution(&mut err);
+        }
+        err.emit();
+    });
+}
+
 fn sized_trait_bound_spans<'tcx>(
     tcx: TyCtxt<'tcx>,
     bounds: hir::GenericBounds<'tcx>,
@@ -246,7 +251,7 @@ fn predicates_reference_self(
     predicates
         .predicates
         .iter()
-        .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
+        .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
         .filter_map(|predicate| predicate_references_self(tcx, predicate))
         .collect()
 }
@@ -257,7 +262,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
         .in_definition_order()
         .filter(|item| item.kind == ty::AssocKind::Type)
         .flat_map(|item| tcx.explicit_item_bounds(item.def_id))
-        .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
+        .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
         .filter_map(|predicate| predicate_references_self(tcx, predicate))
         .collect()
 }
@@ -385,6 +390,8 @@ fn virtual_call_violation_for_method<'tcx>(
     trait_def_id: DefId,
     method: &ty::AssocItem,
 ) -> Option<MethodViolationCode> {
+    let sig = tcx.fn_sig(method.def_id);
+
     // The method's first parameter must be named `self`
     if !method.fn_has_self_parameter {
         // We'll attempt to provide a structured suggestion for `Self: Sized`.
@@ -395,12 +402,22 @@ fn virtual_call_violation_for_method<'tcx>(
                     [.., pred] => (", Self: Sized", pred.span().shrink_to_hi()),
                 },
             );
-        return Some(MethodViolationCode::StaticMethod(sugg));
+        // Get the span pointing at where the `self` receiver should be.
+        let sm = tcx.sess.source_map();
+        let self_span = method.ident.span.to(tcx
+            .hir()
+            .span_if_local(method.def_id)
+            .unwrap_or_else(|| sm.next_point(method.ident.span))
+            .shrink_to_hi());
+        let self_span = sm.span_through_char(self_span, '(').shrink_to_hi();
+        return Some(MethodViolationCode::StaticMethod(
+            sugg,
+            self_span,
+            !sig.inputs().skip_binder().is_empty(),
+        ));
     }
 
-    let sig = tcx.fn_sig(method.def_id);
-
-    for (i, input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() {
+    for (i, &input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() {
         if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
             return Some(MethodViolationCode::ReferencesSelfInput(i));
         }
@@ -423,10 +440,7 @@ fn virtual_call_violation_for_method<'tcx>(
         // so outlives predicates will always hold.
         .cloned()
         .filter(|(p, _)| p.to_opt_type_outlives().is_none())
-        .collect::<Vec<_>>()
-        // Do a shallow visit so that `contains_illegal_self_type_reference`
-        // may apply it's custom visiting.
-        .visit_tys_shallow(|t| contains_illegal_self_type_reference(tcx, trait_def_id, t))
+        .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
     {
         return Some(MethodViolationCode::WhereClauseReferencesSelf);
     }
@@ -448,10 +462,17 @@ fn virtual_call_violation_for_method<'tcx>(
 
             let param_env = tcx.param_env(method.def_id);
 
-            let abi_of_ty = |ty: Ty<'tcx>| -> &Abi {
+            let abi_of_ty = |ty: Ty<'tcx>| -> Option<&Abi> {
                 match tcx.layout_of(param_env.and(ty)) {
-                    Ok(layout) => &layout.abi,
-                    Err(err) => bug!("error: {}\n while computing layout for type {:?}", err, ty),
+                    Ok(layout) => Some(&layout.abi),
+                    Err(err) => {
+                        // #78372
+                        tcx.sess.delay_span_bug(
+                            tcx.def_span(method.def_id),
+                            &format!("error: {}\n while computing layout for type {:?}", err, ty),
+                        );
+                        None
+                    }
                 }
             };
 
@@ -460,7 +481,7 @@ fn virtual_call_violation_for_method<'tcx>(
                 receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id);
 
             match abi_of_ty(unit_receiver_ty) {
-                &Abi::Scalar(..) => (),
+                Some(Abi::Scalar(..)) => (),
                 abi => {
                     tcx.sess.delay_span_bug(
                         tcx.def_span(method.def_id),
@@ -480,13 +501,12 @@ fn virtual_call_violation_for_method<'tcx>(
                 receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id);
 
             match abi_of_ty(trait_object_receiver) {
-                &Abi::ScalarPair(..) => (),
+                Some(Abi::ScalarPair(..)) => (),
                 abi => {
                     tcx.sess.delay_span_bug(
                         tcx.def_span(method.def_id),
                         &format!(
-                            "receiver when `Self = {}` should have a ScalarPair ABI; \
-                                 found {:?}",
+                            "receiver when `Self = {}` should have a ScalarPair ABI; found {:?}",
                             trait_object_ty, abi
                         ),
                     );
@@ -700,10 +720,10 @@ fn receiver_is_dispatchable<'tcx>(
     })
 }
 
-fn contains_illegal_self_type_reference<'tcx>(
+fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
     tcx: TyCtxt<'tcx>,
     trait_def_id: DefId,
-    ty: Ty<'tcx>,
+    value: T,
 ) -> bool {
     // This is somewhat subtle. In general, we want to forbid
     // references to `Self` in the argument and return types,
@@ -746,15 +766,20 @@ fn contains_illegal_self_type_reference<'tcx>(
 
     struct IllegalSelfTypeVisitor<'tcx> {
         tcx: TyCtxt<'tcx>,
-        self_ty: Ty<'tcx>,
         trait_def_id: DefId,
         supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>>,
     }
 
     impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
-        fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
             match t.kind() {
-                ty::Param(_) => t == self.self_ty,
+                ty::Param(_) => {
+                    if t == self.tcx.types.self_param {
+                        ControlFlow::BREAK
+                    } else {
+                        ControlFlow::CONTINUE
+                    }
+                }
                 ty::Projection(ref data) => {
                     // This is a projected type `<Foo as SomeTrait>::X`.
 
@@ -778,7 +803,7 @@ fn contains_illegal_self_type_reference<'tcx>(
                         self.supertraits.as_ref().unwrap().contains(&projection_trait_ref);
 
                     if is_supertrait_of_current_trait {
-                        false // do not walk contained types, do not report error, do collect $200
+                        ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200
                     } else {
                         t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
                     }
@@ -787,22 +812,66 @@ fn contains_illegal_self_type_reference<'tcx>(
             }
         }
 
-        fn visit_const(&mut self, _c: &ty::Const<'tcx>) -> bool {
-            // FIXME(#72219) Look into the unevaluated constants for object safety violations.
-            // Do not walk substitutions of unevaluated consts, as they contain `Self`, even
-            // though the const expression doesn't necessary use it. Currently type variables
-            // inside array length expressions are forbidden, so they can't break the above
-            // rules.
-            false
+        fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<()> {
+            // First check if the type of this constant references `Self`.
+            self.visit_ty(ct.ty)?;
+
+            // Constants can only influence object safety if they reference `Self`.
+            // This is only possible for unevaluated constants, so we walk these here.
+            //
+            // If `AbstractConst::new` returned an error we already failed compilation
+            // so we don't have to emit an additional error here.
+            //
+            // We currently recurse into abstract consts here but do not recurse in
+            // `is_const_evaluatable`. This means that the object safety check is more
+            // liberal than the const eval check.
+            //
+            // 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;
+            if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) {
+                const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node {
+                    Node::Leaf(leaf) => {
+                        let leaf = leaf.subst(self.tcx, ct.substs);
+                        self.visit_const(leaf)
+                    }
+                    Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
+                        ControlFlow::CONTINUE
+                    }
+                })
+            } else {
+                ControlFlow::CONTINUE
+            }
+        }
+
+        fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<()> {
+            if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() {
+                // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for
+                // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to
+                // take a `ty::Const` instead.
+                use rustc_middle::mir::abstract_const::Node;
+                if let Ok(Some(ct)) = AbstractConst::new(self.tcx, def, substs) {
+                    const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node {
+                        Node::Leaf(leaf) => {
+                            let leaf = leaf.subst(self.tcx, ct.substs);
+                            self.visit_const(leaf)
+                        }
+                        Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
+                            ControlFlow::CONTINUE
+                        }
+                    })
+                } else {
+                    ControlFlow::CONTINUE
+                }
+            } else {
+                pred.super_visit_with(self)
+            }
         }
     }
 
-    ty.visit_with(&mut IllegalSelfTypeVisitor {
-        tcx,
-        self_ty: tcx.types.self_param,
-        trait_def_id,
-        supertraits: None,
-    })
+    value
+        .visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None })
+        .is_break()
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index fdf1641c986..b0bfb4ad173 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -642,24 +642,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             debug!(?poly_trait_ref, "assemble_candidates_from_object_ty");
 
+            let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
+            let placeholder_trait_predicate =
+                self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
+
             // Count only those upcast versions that match the trait-ref
             // we are looking for. Specifically, do not only check for the
             // correct trait, but also the correct type parameters.
             // For example, we may be trying to upcast `Foo` to `Bar<i32>`,
             // but `Foo` is declared as `trait Foo: Bar<u32>`.
-            let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref)
-                .filter(|upcast_trait_ref| {
-                    self.infcx
-                        .probe(|_| self.match_poly_trait_ref(obligation, *upcast_trait_ref).is_ok())
+            let candidate_supertraits = util::supertraits(self.tcx(), poly_trait_ref)
+                .enumerate()
+                .filter(|&(_, upcast_trait_ref)| {
+                    self.infcx.probe(|_| {
+                        self.match_normalize_trait_ref(
+                            obligation,
+                            upcast_trait_ref,
+                            placeholder_trait_predicate.trait_ref,
+                        )
+                        .is_ok()
+                    })
                 })
-                .count();
+                .map(|(idx, _)| ObjectCandidate(idx));
 
-            if upcast_trait_refs > 1 {
-                // Can be upcast in many ways; need more type information.
-                candidates.ambiguous = true;
-            } else if upcast_trait_refs == 1 {
-                candidates.vec.push(ObjectCandidate);
-            }
+            candidates.vec.extend(candidate_supertraits);
         })
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 37d619d5942..872b8e85f56 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -69,10 +69,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             ProjectionCandidate(idx) => {
-                let obligations = self.confirm_projection_candidate(obligation, idx);
+                let obligations = self.confirm_projection_candidate(obligation, idx)?;
                 Ok(ImplSource::Param(obligations))
             }
 
+            ObjectCandidate(idx) => {
+                let data = self.confirm_object_candidate(obligation, idx)?;
+                Ok(ImplSource::Object(data))
+            }
+
             ClosureCandidate => {
                 let vtable_closure = self.confirm_closure_candidate(obligation)?;
                 Ok(ImplSource::Closure(vtable_closure))
@@ -97,11 +102,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Ok(ImplSource::TraitAlias(data))
             }
 
-            ObjectCandidate => {
-                let data = self.confirm_object_candidate(obligation);
-                Ok(ImplSource::Object(data))
-            }
-
             BuiltinObjectCandidate => {
                 // This indicates something like `Trait + Send: Send`. In this case, we know that
                 // this holds because that's what the object type is telling us, and there's really
@@ -120,7 +120,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &TraitObligation<'tcx>,
         idx: usize,
-    ) -> Vec<PredicateObligation<'tcx>> {
+    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
         self.infcx.commit_unconditionally(|_| {
             let tcx = self.tcx();
 
@@ -148,19 +148,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 &mut obligations,
             );
 
-            obligations.extend(
+            obligations.extend(self.infcx.commit_if_ok(|_| {
                 self.infcx
                     .at(&obligation.cause, obligation.param_env)
                     .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate)
                     .map(|InferOk { obligations, .. }| obligations)
-                    .unwrap_or_else(|_| {
-                        bug!(
-                            "Projection bound `{:?}` was applicable to `{:?}` but now is not",
-                            candidate,
-                            obligation
-                        );
-                    }),
-            );
+                    .map_err(|_| Unimplemented)
+            })?);
 
             if let ty::Projection(..) = placeholder_self_ty.kind() {
                 for predicate in tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates {
@@ -181,7 +175,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             }
 
-            obligations
+            Ok(obligations)
         })
     }
 
@@ -371,9 +365,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_object_candidate(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-    ) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> {
-        debug!(?obligation, "confirm_object_candidate");
+        index: usize,
+    ) -> Result<ImplSourceObjectData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
         let tcx = self.tcx();
+        debug!(?obligation, ?index, "confirm_object_candidate");
 
         let trait_predicate =
             self.infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
@@ -399,43 +394,39 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             })
             .with_self_ty(self.tcx(), self_ty);
 
-        let mut upcast_trait_ref = None;
         let mut nested = vec![];
-        let vtable_base;
 
-        {
-            // We want to find the first supertrait in the list of
-            // supertraits that we can unify with, and do that
-            // unification. We know that there is exactly one in the list
-            // where we can unify, because otherwise select would have
-            // reported an ambiguity. (When we do find a match, also
-            // record it for later.)
-            let nonmatching = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref))
-                .take_while(|&t| {
-                    match self.infcx.commit_if_ok(|_| {
-                        self.infcx
-                            .at(&obligation.cause, obligation.param_env)
-                            .sup(obligation_trait_ref, t)
-                            .map(|InferOk { obligations, .. }| obligations)
-                            .map_err(|_| ())
-                    }) {
-                        Ok(obligations) => {
-                            upcast_trait_ref = Some(t);
-                            nested.extend(obligations);
-                            false
-                        }
-                        Err(_) => true,
-                    }
-                });
+        let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref));
 
-            // Additionally, for each of the non-matching predicates that
-            // we pass over, we sum up the set of number of vtable
-            // entries, so that we can compute the offset for the selected
-            // trait.
-            vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
-        }
+        // For each of the non-matching predicates that
+        // we pass over, we sum up the set of number of vtable
+        // entries, so that we can compute the offset for the selected
+        // trait.
+        let vtable_base = supertraits
+            .by_ref()
+            .take(index)
+            .map(|t| super::util::count_own_vtable_entries(tcx, t))
+            .sum();
+
+        let unnormalized_upcast_trait_ref =
+            supertraits.next().expect("supertraits iterator no longer has as many elements");
+
+        let upcast_trait_ref = normalize_with_depth_to(
+            self,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            &unnormalized_upcast_trait_ref,
+            &mut nested,
+        );
 
-        let upcast_trait_ref = upcast_trait_ref.unwrap();
+        nested.extend(self.infcx.commit_if_ok(|_| {
+            self.infcx
+                .at(&obligation.cause, obligation.param_env)
+                .sup(obligation_trait_ref, upcast_trait_ref)
+                .map(|InferOk { obligations, .. }| obligations)
+                .map_err(|_| Unimplemented)
+        })?);
 
         // Check supertraits hold. This is so that their associated type bounds
         // will be checked in the code below.
@@ -501,7 +492,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         debug!(?nested, "object nested obligations");
-        ImplSourceObjectData { upcast_trait_ref, vtable_base, nested }
+        Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested })
     }
 
     fn confirm_fn_pointer_candidate(
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index b838602e76c..4cc4bc0acda 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -518,12 +518,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             result
                         }
                         Ok(Ok(None)) => Ok(EvaluatedToAmbig),
-                        // EvaluatedToRecur might also be acceptable here, but use
-                        // Unknown for now because it means that we won't dismiss a
-                        // selection candidate solely because it has a projection
-                        // cycle. This is closest to the previous behavior of
-                        // immediately erroring.
-                        Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown),
+                        Ok(Err(project::InProgress)) => Ok(EvaluatedToRecur),
                         Err(_) => Ok(EvaluatedToErr),
                     }
                 }
@@ -1179,7 +1174,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 if let ty::PredicateAtom::Trait(pred, _) = bound_predicate.skip_binder() {
                     let bound = bound_predicate.rebind(pred.trait_ref);
                     if self.infcx.probe(|_| {
-                        match self.match_projection(
+                        match self.match_normalize_trait_ref(
                             obligation,
                             bound,
                             placeholder_trait_predicate.trait_ref,
@@ -1207,7 +1202,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// Equates the trait in `obligation` with trait bound. If the two traits
     /// can be equated and the normalized trait bound doesn't contain inference
     /// variables or placeholders, the normalized bound is returned.
-    fn match_projection(
+    fn match_normalize_trait_ref(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         trait_bound: ty::PolyTraitRef<'tcx>,
@@ -1357,10 +1352,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | BuiltinUnsizeCandidate
                 | BuiltinCandidate { .. }
                 | TraitAliasCandidate(..)
-                | ObjectCandidate
+                | ObjectCandidate(_)
                 | ProjectionCandidate(_),
             ) => !is_global(cand),
-            (ObjectCandidate | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
+            (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
                 // Prefer these to a global where-clause bound
                 // (see issue #50825).
                 is_global(cand)
@@ -1381,20 +1376,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 is_global(cand) && other.evaluation.must_apply_modulo_regions()
             }
 
-            (ProjectionCandidate(i), ProjectionCandidate(j)) => {
-                // Arbitrarily pick the first candidate for backwards
+            (ProjectionCandidate(i), ProjectionCandidate(j))
+            | (ObjectCandidate(i), ObjectCandidate(j)) => {
+                // Arbitrarily pick the lower numbered candidate for backwards
                 // compatibility reasons. Don't let this affect inference.
-                i > j && !needs_infer
+                i < j && !needs_infer
             }
-            (ObjectCandidate, ObjectCandidate) => bug!("Duplicate object candidate"),
-            (ObjectCandidate, ProjectionCandidate(_))
-            | (ProjectionCandidate(_), ObjectCandidate) => {
+            (ObjectCandidate(_), ProjectionCandidate(_))
+            | (ProjectionCandidate(_), ObjectCandidate(_)) => {
                 bug!("Have both object and projection candidate")
             }
 
             // Arbitrarily give projection and object candidates priority.
             (
-                ObjectCandidate | ProjectionCandidate(_),
+                ObjectCandidate(_) | ProjectionCandidate(_),
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
@@ -1414,7 +1409,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | BuiltinUnsizeCandidate
                 | BuiltinCandidate { .. }
                 | TraitAliasCandidate(..),
-                ObjectCandidate | ProjectionCandidate(_),
+                ObjectCandidate(_) | ProjectionCandidate(_),
             ) => false,
 
             (&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
@@ -1890,9 +1885,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     /// Normalize `where_clause_trait_ref` and try to match it against
     /// `obligation`. If successful, return any predicates that
-    /// result from the normalization. Normalization is necessary
-    /// because where-clauses are stored in the parameter environment
-    /// unnormalized.
+    /// result from the normalization.
     fn match_where_clause_trait_ref(
         &mut self,
         obligation: &TraitObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 4f7fa2c3988..ce0d3ef8a6a 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -8,6 +8,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_span::Span;
+use std::ops::ControlFlow;
 
 #[derive(Debug)]
 pub enum NonStructuralMatchTy<'tcx> {
@@ -134,38 +135,38 @@ impl Search<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
         debug!("Search visiting ty: {:?}", ty);
 
         let (adt_def, substs) = match *ty.kind() {
             ty::Adt(adt_def, substs) => (adt_def, substs),
             ty::Param(_) => {
                 self.found = Some(NonStructuralMatchTy::Param);
-                return true; // Stop visiting.
+                return ControlFlow::BREAK;
             }
             ty::Dynamic(..) => {
                 self.found = Some(NonStructuralMatchTy::Dynamic);
-                return true; // Stop visiting.
+                return ControlFlow::BREAK;
             }
             ty::Foreign(_) => {
                 self.found = Some(NonStructuralMatchTy::Foreign);
-                return true; // Stop visiting.
+                return ControlFlow::BREAK;
             }
             ty::Opaque(..) => {
                 self.found = Some(NonStructuralMatchTy::Opaque);
-                return true; // Stop visiting.
+                return ControlFlow::BREAK;
             }
             ty::Projection(..) => {
                 self.found = Some(NonStructuralMatchTy::Projection);
-                return true; // Stop visiting.
+                return ControlFlow::BREAK;
             }
             ty::Generator(..) | ty::GeneratorWitness(..) => {
                 self.found = Some(NonStructuralMatchTy::Generator);
-                return true; // Stop visiting.
+                return ControlFlow::BREAK;
             }
             ty::Closure(..) => {
                 self.found = Some(NonStructuralMatchTy::Closure);
-                return true; // Stop visiting.
+                return ControlFlow::BREAK;
             }
             ty::RawPtr(..) => {
                 // structural-match ignores substructure of
@@ -182,39 +183,31 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
                 // Even though `NonStructural` does not implement `PartialEq`,
                 // structural equality on `T` does not recur into the raw
                 // pointer. Therefore, one can still use `C` in a pattern.
-
-                // (But still tell the caller to continue search.)
-                return false;
+                return ControlFlow::CONTINUE;
             }
             ty::FnDef(..) | ty::FnPtr(..) => {
                 // Types of formals and return in `fn(_) -> _` are also irrelevant;
                 // so we do not recur into them via `super_visit_with`
-                //
-                // (But still tell the caller to continue search.)
-                return false;
+                return ControlFlow::CONTINUE;
             }
             ty::Array(_, n)
                 if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
             {
                 // rust-lang/rust#62336: ignore type of contents
                 // for empty array.
-                //
-                // (But still tell the caller to continue search.)
-                return false;
+                return ControlFlow::CONTINUE;
             }
             ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
                 // These primitive types are always structural match.
                 //
                 // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
-                //
-                // (But still tell the caller to continue search.)
-                return false;
+                return ControlFlow::CONTINUE;
             }
 
             ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
                 // First check all contained types and then tell the caller to continue searching.
                 ty.super_visit_with(self);
-                return false;
+                return ControlFlow::CONTINUE;
             }
             ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
                 bug!("unexpected type during structural-match checking: {:?}", ty);
@@ -223,22 +216,19 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
                 self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check");
                 // We still want to check other types after encountering an error,
                 // as this may still emit relevant errors.
-                //
-                // So we continue searching here.
-                return false;
+                return ControlFlow::CONTINUE;
             }
         };
 
         if !self.seen.insert(adt_def.did) {
             debug!("Search already seen adt_def: {:?}", adt_def);
-            // Let caller continue its search.
-            return false;
+            return ControlFlow::CONTINUE;
         }
 
         if !self.type_marked_structural(ty) {
             debug!("Search found ty: {:?}", ty);
             self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
-            return true; // Halt visiting!
+            return ControlFlow::BREAK;
         }
 
         // structural-match does not care about the
@@ -258,16 +248,16 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
             let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty);
             debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty);
 
-            if ty.visit_with(self) {
+            if ty.visit_with(self).is_break() {
                 // found an ADT without structural-match; halt visiting!
                 assert!(self.found.is_some());
-                return true;
+                return ControlFlow::BREAK;
             }
         }
 
         // Even though we do not want to recur on substs, we do
         // want our caller to continue its own search.
-        false
+        ControlFlow::CONTINUE
     }
 }