about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs59
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs17
-rw-r--r--compiler/rustc_lint/src/builtin.rs19
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs397
-rw-r--r--compiler/rustc_target/src/spec/loongarch64_unknown_none_softfloat.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs164
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rw-r--r--src/tools/rustdoc-gui/tester.js4
-rw-r--r--tests/rustdoc-gui/shortcuts.goml6
-rw-r--r--tests/rustdoc-gui/source-code-page.goml24
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr21
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr20
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr20
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.rs21
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.stderr74
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr12
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr12
-rw-r--r--tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr9
-rw-r--r--tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr9
-rw-r--r--tests/ui/impl-trait/in-trait/unconstrained-lt.rs16
-rw-r--r--tests/ui/rust-2018/edition-lint-infer-outlives.fixed6
-rw-r--r--tests/ui/rust-2018/edition-lint-infer-outlives.rs8
-rw-r--r--tests/ui/rust-2018/edition-lint-infer-outlives.stderr11
24 files changed, 531 insertions, 406 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index dce31975dbc..4fbe68b8b6c 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -45,12 +45,7 @@ pub(super) fn compare_impl_method<'tcx>(
     debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
 
     let _: Result<_, ErrorGuaranteed> = try {
-        compare_self_type(tcx, impl_m, trait_m, impl_trait_ref)?;
-        compare_number_of_generics(tcx, impl_m, trait_m, false)?;
-        compare_generic_param_kinds(tcx, impl_m, trait_m, false)?;
-        compare_number_of_method_arguments(tcx, impl_m, trait_m)?;
-        compare_synthetic_generics(tcx, impl_m, trait_m)?;
-        compare_asyncness(tcx, impl_m, trait_m)?;
+        check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
         compare_method_predicate_entailment(
             tcx,
             impl_m,
@@ -61,6 +56,26 @@ pub(super) fn compare_impl_method<'tcx>(
     };
 }
 
+/// Checks a bunch of different properties of the impl/trait methods for
+/// compatibility, such as asyncness, number of argument, self receiver kind,
+/// and number of early- and late-bound generics.
+fn check_method_is_structurally_compatible<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: ty::AssocItem,
+    trait_m: ty::AssocItem,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+    delay: bool,
+) -> Result<(), ErrorGuaranteed> {
+    compare_self_type(tcx, impl_m, trait_m, impl_trait_ref, delay)?;
+    compare_number_of_generics(tcx, impl_m, trait_m, delay)?;
+    compare_generic_param_kinds(tcx, impl_m, trait_m, delay)?;
+    compare_number_of_method_arguments(tcx, impl_m, trait_m, delay)?;
+    compare_synthetic_generics(tcx, impl_m, trait_m, delay)?;
+    compare_asyncness(tcx, impl_m, trait_m, delay)?;
+    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, delay)?;
+    Ok(())
+}
+
 /// This function is best explained by example. Consider a trait with it's implementation:
 ///
 /// ```rust
@@ -177,9 +192,6 @@ fn compare_method_predicate_entailment<'tcx>(
     let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
     let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
 
-    // Check region bounds.
-    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?;
-
     // Create obligations for each predicate declared by the impl
     // definition in the context of the trait's parameter
     // environment. We can't just use `impl_env.caller_bounds`,
@@ -534,6 +546,7 @@ fn compare_asyncness<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: ty::AssocItem,
     trait_m: ty::AssocItem,
+    delay: bool,
 ) -> Result<(), ErrorGuaranteed> {
     if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
         match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() {
@@ -544,11 +557,14 @@ fn compare_asyncness<'tcx>(
                 // We don't know if it's ok, but at least it's already an error.
             }
             _ => {
-                return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
-                    span: tcx.def_span(impl_m.def_id),
-                    method_name: trait_m.name,
-                    trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
-                }));
+                return Err(tcx
+                    .sess
+                    .create_err(crate::errors::AsyncTraitImplShouldBeAsync {
+                        span: tcx.def_span(impl_m.def_id),
+                        method_name: trait_m.name,
+                        trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
+                    })
+                    .emit_unless(delay));
             }
         };
     }
@@ -602,9 +618,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
 
     // First, check a few of the same things as `compare_impl_method`,
     // just so we don't ICE during substitution later.
-    compare_number_of_generics(tcx, impl_m, trait_m, true)?;
-    compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
-    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
+    check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
 
     let trait_to_impl_substs = impl_trait_ref.substs;
 
@@ -1097,6 +1111,7 @@ fn compare_self_type<'tcx>(
     impl_m: ty::AssocItem,
     trait_m: ty::AssocItem,
     impl_trait_ref: ty::TraitRef<'tcx>,
+    delay: bool,
 ) -> Result<(), ErrorGuaranteed> {
     // Try to give more informative error messages about self typing
     // mismatches. Note that any mismatch will also be detected
@@ -1145,7 +1160,7 @@ fn compare_self_type<'tcx>(
             } else {
                 err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
             }
-            return Err(err.emit());
+            return Err(err.emit_unless(delay));
         }
 
         (true, false) => {
@@ -1166,7 +1181,7 @@ fn compare_self_type<'tcx>(
                 err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
             }
 
-            return Err(err.emit());
+            return Err(err.emit_unless(delay));
         }
     }
 
@@ -1352,6 +1367,7 @@ fn compare_number_of_method_arguments<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: ty::AssocItem,
     trait_m: ty::AssocItem,
+    delay: bool,
 ) -> Result<(), ErrorGuaranteed> {
     let impl_m_fty = tcx.fn_sig(impl_m.def_id);
     let trait_m_fty = tcx.fn_sig(trait_m.def_id);
@@ -1422,7 +1438,7 @@ fn compare_number_of_method_arguments<'tcx>(
             ),
         );
 
-        return Err(err.emit());
+        return Err(err.emit_unless(delay));
     }
 
     Ok(())
@@ -1432,6 +1448,7 @@ fn compare_synthetic_generics<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: ty::AssocItem,
     trait_m: ty::AssocItem,
+    delay: bool,
 ) -> Result<(), ErrorGuaranteed> {
     // FIXME(chrisvittal) Clean up this function, list of FIXME items:
     //     1. Better messages for the span labels
@@ -1551,7 +1568,7 @@ fn compare_synthetic_generics<'tcx>(
                 }
                 _ => unreachable!(),
             }
-            error_found = Some(err.emit());
+            error_found = Some(err.emit_unless(delay));
         }
     }
     if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 612d4ff3df8..5526dd4b007 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -106,10 +106,23 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
                     if item.defaultness(tcx).has_value() {
                         cgp::parameters_for(&tcx.type_of(def_id).subst_identity(), true)
                     } else {
-                        Vec::new()
+                        vec![]
                     }
                 }
-                ty::AssocKind::Fn | ty::AssocKind::Const => Vec::new(),
+                ty::AssocKind::Fn => {
+                    if !tcx.lower_impl_trait_in_trait_to_assoc_ty()
+                        && item.defaultness(tcx).has_value()
+                        && tcx.impl_method_has_trait_impl_trait_tys(item.def_id)
+                        && let Ok(table) = tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
+                    {
+                        table.values().copied().flat_map(|ty| {
+                            cgp::parameters_for(&ty.subst_identity(), true)
+                        }).collect()
+                    } else {
+                        vec![]
+                    }
+                }
+                ty::AssocKind::Const => vec![],
             }
         })
         .collect();
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index ff2989112af..7b05bff5151 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2124,12 +2124,16 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
             }
 
             let ty_generics = cx.tcx.generics_of(def_id);
+            let num_where_predicates = hir_generics
+                .predicates
+                .iter()
+                .filter(|predicate| predicate.in_where_clause())
+                .count();
 
             let mut bound_count = 0;
             let mut lint_spans = Vec::new();
             let mut where_lint_spans = Vec::new();
-            let mut dropped_predicate_count = 0;
-            let num_predicates = hir_generics.predicates.len();
+            let mut dropped_where_predicate_count = 0;
             for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
                 let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
                     match where_predicate {
@@ -2186,8 +2190,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                 bound_count += bound_spans.len();
 
                 let drop_predicate = bound_spans.len() == bounds.len();
-                if drop_predicate {
-                    dropped_predicate_count += 1;
+                if drop_predicate && in_where_clause {
+                    dropped_where_predicate_count += 1;
                 }
 
                 if drop_predicate {
@@ -2196,7 +2200,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                     } else if predicate_span.from_expansion() {
                         // Don't try to extend the span if it comes from a macro expansion.
                         where_lint_spans.push(predicate_span);
-                    } else if i + 1 < num_predicates {
+                    } else if i + 1 < num_where_predicates {
                         // If all the bounds on a predicate were inferable and there are
                         // further predicates, we want to eat the trailing comma.
                         let next_predicate_span = hir_generics.predicates[i + 1].span();
@@ -2224,9 +2228,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                 }
             }
 
-            // If all predicates are inferable, drop the entire clause
+            // If all predicates in where clause are inferable, drop the entire clause
             // (including the `where`)
-            if hir_generics.has_where_clause_predicates && dropped_predicate_count == num_predicates
+            if hir_generics.has_where_clause_predicates
+                && dropped_where_predicate_count == num_where_predicates
             {
                 let where_span = hir_generics.where_clause_span;
                 // Extend the where clause back to the closing `>` of the
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 6d8d99cfb5f..6bd030b13d1 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -8,6 +8,7 @@
 //! For now, we are developing everything inside `rustc`, thus, we keep this module private.
 
 use crate::stable_mir::{self, ty::TyKind, Context};
+use rustc_middle::mir;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use tracing::debug;
@@ -42,8 +43,8 @@ impl<'tcx> Context for Tables<'tcx> {
                 .basic_blocks
                 .iter()
                 .map(|block| stable_mir::mir::BasicBlock {
-                    terminator: rustc_terminator_to_terminator(block.terminator()),
-                    statements: block.statements.iter().map(rustc_statement_to_statement).collect(),
+                    terminator: block.terminator().stable(),
+                    statements: block.statements.iter().map(mir::Statement::stable).collect(),
                 })
                 .collect(),
             locals: mir.local_decls.iter().map(|decl| self.intern_ty(decl.ty)).collect(),
@@ -118,82 +119,95 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
     stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
 }
 
-fn rustc_statement_to_statement(
-    s: &rustc_middle::mir::Statement<'_>,
-) -> stable_mir::mir::Statement {
-    use rustc_middle::mir::StatementKind::*;
-    match &s.kind {
-        Assign(assign) => stable_mir::mir::Statement::Assign(
-            rustc_place_to_place(&assign.0),
-            rustc_rvalue_to_rvalue(&assign.1),
-        ),
-        FakeRead(_) => todo!(),
-        SetDiscriminant { .. } => todo!(),
-        Deinit(_) => todo!(),
-        StorageLive(_) => todo!(),
-        StorageDead(_) => todo!(),
-        Retag(_, _) => todo!(),
-        PlaceMention(_) => todo!(),
-        AscribeUserType(_, _) => todo!(),
-        Coverage(_) => todo!(),
-        Intrinsic(_) => todo!(),
-        ConstEvalCounter => todo!(),
-        Nop => stable_mir::mir::Statement::Nop,
+pub trait Stable {
+    type T;
+    fn stable(&self) -> Self::T;
+}
+
+impl<'tcx> Stable for mir::Statement<'tcx> {
+    type T = stable_mir::mir::Statement;
+    fn stable(&self) -> Self::T {
+        use rustc_middle::mir::StatementKind::*;
+        match &self.kind {
+            Assign(assign) => {
+                stable_mir::mir::Statement::Assign(assign.0.stable(), assign.1.stable())
+            }
+            FakeRead(_) => todo!(),
+            SetDiscriminant { .. } => todo!(),
+            Deinit(_) => todo!(),
+            StorageLive(_) => todo!(),
+            StorageDead(_) => todo!(),
+            Retag(_, _) => todo!(),
+            PlaceMention(_) => todo!(),
+            AscribeUserType(_, _) => todo!(),
+            Coverage(_) => todo!(),
+            Intrinsic(_) => todo!(),
+            ConstEvalCounter => todo!(),
+            Nop => stable_mir::mir::Statement::Nop,
+        }
     }
 }
 
-fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Rvalue {
-    use rustc_middle::mir::Rvalue::*;
-    match rvalue {
-        Use(op) => stable_mir::mir::Rvalue::Use(rustc_op_to_op(op)),
-        Repeat(_, _) => todo!(),
-        Ref(_, _, _) => todo!(),
-        ThreadLocalRef(_) => todo!(),
-        AddressOf(_, _) => todo!(),
-        Len(_) => todo!(),
-        Cast(_, _, _) => todo!(),
-        BinaryOp(_, _) => todo!(),
-        CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
-            rustc_bin_op_to_bin_op(bin_op),
-            rustc_op_to_op(&ops.0),
-            rustc_op_to_op(&ops.1),
-        ),
-        NullaryOp(_, _) => todo!(),
-        UnaryOp(un_op, op) => {
-            stable_mir::mir::Rvalue::UnaryOp(rustc_un_op_to_un_op(un_op), rustc_op_to_op(op))
+impl<'tcx> Stable for mir::Rvalue<'tcx> {
+    type T = stable_mir::mir::Rvalue;
+    fn stable(&self) -> Self::T {
+        use mir::Rvalue::*;
+        match self {
+            Use(op) => stable_mir::mir::Rvalue::Use(op.stable()),
+            Repeat(_, _) => todo!(),
+            Ref(_, _, _) => todo!(),
+            ThreadLocalRef(_) => todo!(),
+            AddressOf(_, _) => todo!(),
+            Len(_) => todo!(),
+            Cast(_, _, _) => todo!(),
+            BinaryOp(_, _) => todo!(),
+            CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
+                bin_op.stable(),
+                ops.0.stable(),
+                ops.1.stable(),
+            ),
+            NullaryOp(_, _) => todo!(),
+            UnaryOp(un_op, op) => stable_mir::mir::Rvalue::UnaryOp(un_op.stable(), op.stable()),
+            Discriminant(_) => todo!(),
+            Aggregate(_, _) => todo!(),
+            ShallowInitBox(_, _) => todo!(),
+            CopyForDeref(_) => todo!(),
         }
-        Discriminant(_) => todo!(),
-        Aggregate(_, _) => todo!(),
-        ShallowInitBox(_, _) => todo!(),
-        CopyForDeref(_) => todo!(),
     }
 }
 
-fn rustc_op_to_op(op: &rustc_middle::mir::Operand<'_>) -> stable_mir::mir::Operand {
-    use rustc_middle::mir::Operand::*;
-    match op {
-        Copy(place) => stable_mir::mir::Operand::Copy(rustc_place_to_place(place)),
-        Move(place) => stable_mir::mir::Operand::Move(rustc_place_to_place(place)),
-        Constant(c) => stable_mir::mir::Operand::Constant(c.to_string()),
+impl<'tcx> Stable for mir::Operand<'tcx> {
+    type T = stable_mir::mir::Operand;
+    fn stable(&self) -> Self::T {
+        use mir::Operand::*;
+        match self {
+            Copy(place) => stable_mir::mir::Operand::Copy(place.stable()),
+            Move(place) => stable_mir::mir::Operand::Move(place.stable()),
+            Constant(c) => stable_mir::mir::Operand::Constant(c.to_string()),
+        }
     }
 }
 
-fn rustc_place_to_place(place: &rustc_middle::mir::Place<'_>) -> stable_mir::mir::Place {
-    stable_mir::mir::Place {
-        local: place.local.as_usize(),
-        projection: format!("{:?}", place.projection),
+impl<'tcx> Stable for mir::Place<'tcx> {
+    type T = stable_mir::mir::Place;
+    fn stable(&self) -> Self::T {
+        stable_mir::mir::Place {
+            local: self.local.as_usize(),
+            projection: format!("{:?}", self.projection),
+        }
     }
 }
 
-fn rustc_unwind_to_unwind(
-    unwind: &rustc_middle::mir::UnwindAction,
-) -> stable_mir::mir::UnwindAction {
-    use rustc_middle::mir::UnwindAction;
-    match unwind {
-        UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue,
-        UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable,
-        UnwindAction::Terminate => stable_mir::mir::UnwindAction::Terminate,
-        UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()),
+impl Stable for mir::UnwindAction {
+    type T = stable_mir::mir::UnwindAction;
+    fn stable(&self) -> Self::T {
+        use rustc_middle::mir::UnwindAction;
+        match self {
+            UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue,
+            UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable,
+            UnwindAction::Terminate => stable_mir::mir::UnwindAction::Terminate,
+            UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()),
+        }
     }
 }
 
@@ -202,168 +216,163 @@ fn rustc_assert_msg_to_msg<'tcx>(
 ) -> stable_mir::mir::AssertMessage {
     use rustc_middle::mir::AssertKind;
     match assert_message {
-        AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck {
-            len: rustc_op_to_op(len),
-            index: rustc_op_to_op(index),
-        },
-        AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow(
-            rustc_bin_op_to_bin_op(bin_op),
-            rustc_op_to_op(op1),
-            rustc_op_to_op(op2),
-        ),
-        AssertKind::OverflowNeg(op) => {
-            stable_mir::mir::AssertMessage::OverflowNeg(rustc_op_to_op(op))
+        AssertKind::BoundsCheck { len, index } => {
+            stable_mir::mir::AssertMessage::BoundsCheck { len: len.stable(), index: index.stable() }
+        }
+        AssertKind::Overflow(bin_op, op1, op2) => {
+            stable_mir::mir::AssertMessage::Overflow(bin_op.stable(), op1.stable(), op2.stable())
         }
+        AssertKind::OverflowNeg(op) => stable_mir::mir::AssertMessage::OverflowNeg(op.stable()),
         AssertKind::DivisionByZero(op) => {
-            stable_mir::mir::AssertMessage::DivisionByZero(rustc_op_to_op(op))
+            stable_mir::mir::AssertMessage::DivisionByZero(op.stable())
         }
         AssertKind::RemainderByZero(op) => {
-            stable_mir::mir::AssertMessage::RemainderByZero(rustc_op_to_op(op))
+            stable_mir::mir::AssertMessage::RemainderByZero(op.stable())
         }
         AssertKind::ResumedAfterReturn(generator) => {
-            stable_mir::mir::AssertMessage::ResumedAfterReturn(rustc_generator_to_generator(
-                generator,
-            ))
+            stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable())
         }
         AssertKind::ResumedAfterPanic(generator) => {
-            stable_mir::mir::AssertMessage::ResumedAfterPanic(rustc_generator_to_generator(
-                generator,
-            ))
+            stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable())
         }
         AssertKind::MisalignedPointerDereference { required, found } => {
             stable_mir::mir::AssertMessage::MisalignedPointerDereference {
-                required: rustc_op_to_op(required),
-                found: rustc_op_to_op(found),
+                required: required.stable(),
+                found: found.stable(),
             }
         }
     }
 }
 
-fn rustc_bin_op_to_bin_op(bin_op: &rustc_middle::mir::BinOp) -> stable_mir::mir::BinOp {
-    use rustc_middle::mir::BinOp;
-    match bin_op {
-        BinOp::Add => stable_mir::mir::BinOp::Add,
-        BinOp::Sub => stable_mir::mir::BinOp::Sub,
-        BinOp::Mul => stable_mir::mir::BinOp::Mul,
-        BinOp::Div => stable_mir::mir::BinOp::Div,
-        BinOp::Rem => stable_mir::mir::BinOp::Rem,
-        BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
-        BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd,
-        BinOp::BitOr => stable_mir::mir::BinOp::BitOr,
-        BinOp::Shl => stable_mir::mir::BinOp::Shl,
-        BinOp::Shr => stable_mir::mir::BinOp::Shr,
-        BinOp::Eq => stable_mir::mir::BinOp::Eq,
-        BinOp::Lt => stable_mir::mir::BinOp::Lt,
-        BinOp::Le => stable_mir::mir::BinOp::Le,
-        BinOp::Ne => stable_mir::mir::BinOp::Ne,
-        BinOp::Ge => stable_mir::mir::BinOp::Ge,
-        BinOp::Gt => stable_mir::mir::BinOp::Gt,
-        BinOp::Offset => stable_mir::mir::BinOp::Offset,
+impl Stable for mir::BinOp {
+    type T = stable_mir::mir::BinOp;
+    fn stable(&self) -> Self::T {
+        use mir::BinOp;
+        match self {
+            BinOp::Add => stable_mir::mir::BinOp::Add,
+            BinOp::Sub => stable_mir::mir::BinOp::Sub,
+            BinOp::Mul => stable_mir::mir::BinOp::Mul,
+            BinOp::Div => stable_mir::mir::BinOp::Div,
+            BinOp::Rem => stable_mir::mir::BinOp::Rem,
+            BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
+            BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd,
+            BinOp::BitOr => stable_mir::mir::BinOp::BitOr,
+            BinOp::Shl => stable_mir::mir::BinOp::Shl,
+            BinOp::Shr => stable_mir::mir::BinOp::Shr,
+            BinOp::Eq => stable_mir::mir::BinOp::Eq,
+            BinOp::Lt => stable_mir::mir::BinOp::Lt,
+            BinOp::Le => stable_mir::mir::BinOp::Le,
+            BinOp::Ne => stable_mir::mir::BinOp::Ne,
+            BinOp::Ge => stable_mir::mir::BinOp::Ge,
+            BinOp::Gt => stable_mir::mir::BinOp::Gt,
+            BinOp::Offset => stable_mir::mir::BinOp::Offset,
+        }
     }
 }
 
-fn rustc_un_op_to_un_op(unary_op: &rustc_middle::mir::UnOp) -> stable_mir::mir::UnOp {
-    use rustc_middle::mir::UnOp;
-    match unary_op {
-        UnOp::Not => stable_mir::mir::UnOp::Not,
-        UnOp::Neg => stable_mir::mir::UnOp::Neg,
+impl Stable for mir::UnOp {
+    type T = stable_mir::mir::UnOp;
+    fn stable(&self) -> Self::T {
+        use mir::UnOp;
+        match self {
+            UnOp::Not => stable_mir::mir::UnOp::Not,
+            UnOp::Neg => stable_mir::mir::UnOp::Neg,
+        }
     }
 }
 
-fn rustc_generator_to_generator(
-    generator: &rustc_hir::GeneratorKind,
-) -> stable_mir::mir::GeneratorKind {
-    use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
-    match generator {
-        GeneratorKind::Async(async_gen) => {
-            let async_gen = match async_gen {
-                AsyncGeneratorKind::Block => stable_mir::mir::AsyncGeneratorKind::Block,
-                AsyncGeneratorKind::Closure => stable_mir::mir::AsyncGeneratorKind::Closure,
-                AsyncGeneratorKind::Fn => stable_mir::mir::AsyncGeneratorKind::Fn,
-            };
-            stable_mir::mir::GeneratorKind::Async(async_gen)
+impl Stable for rustc_hir::GeneratorKind {
+    type T = stable_mir::mir::GeneratorKind;
+    fn stable(&self) -> Self::T {
+        use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
+        match self {
+            GeneratorKind::Async(async_gen) => {
+                let async_gen = match async_gen {
+                    AsyncGeneratorKind::Block => stable_mir::mir::AsyncGeneratorKind::Block,
+                    AsyncGeneratorKind::Closure => stable_mir::mir::AsyncGeneratorKind::Closure,
+                    AsyncGeneratorKind::Fn => stable_mir::mir::AsyncGeneratorKind::Fn,
+                };
+                stable_mir::mir::GeneratorKind::Async(async_gen)
+            }
+            GeneratorKind::Gen => stable_mir::mir::GeneratorKind::Gen,
         }
-        GeneratorKind::Gen => stable_mir::mir::GeneratorKind::Gen,
     }
 }
 
-fn rustc_inline_asm_operand_to_inline_asm_operand(
-    operand: &rustc_middle::mir::InlineAsmOperand<'_>,
-) -> stable_mir::mir::InlineAsmOperand {
-    use rustc_middle::mir::InlineAsmOperand;
+impl<'tcx> Stable for mir::InlineAsmOperand<'tcx> {
+    type T = stable_mir::mir::InlineAsmOperand;
+    fn stable(&self) -> Self::T {
+        use rustc_middle::mir::InlineAsmOperand;
 
-    let (in_value, out_place) = match operand {
-        InlineAsmOperand::In { value, .. } => (Some(rustc_op_to_op(value)), None),
-        InlineAsmOperand::Out { place, .. } => {
-            (None, place.map(|place| rustc_place_to_place(&place)))
-        }
-        InlineAsmOperand::InOut { in_value, out_place, .. } => {
-            (Some(rustc_op_to_op(in_value)), out_place.map(|place| rustc_place_to_place(&place)))
-        }
-        InlineAsmOperand::Const { .. }
-        | InlineAsmOperand::SymFn { .. }
-        | InlineAsmOperand::SymStatic { .. } => (None, None),
-    };
+        let (in_value, out_place) = match self {
+            InlineAsmOperand::In { value, .. } => (Some(value.stable()), None),
+            InlineAsmOperand::Out { place, .. } => (None, place.map(|place| place.stable())),
+            InlineAsmOperand::InOut { in_value, out_place, .. } => {
+                (Some(in_value.stable()), out_place.map(|place| place.stable()))
+            }
+            InlineAsmOperand::Const { .. }
+            | InlineAsmOperand::SymFn { .. }
+            | InlineAsmOperand::SymStatic { .. } => (None, None),
+        };
 
-    stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{:?}", operand) }
+        stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{:?}", self) }
+    }
 }
 
-fn rustc_terminator_to_terminator(
-    terminator: &rustc_middle::mir::Terminator<'_>,
-) -> stable_mir::mir::Terminator {
-    use rustc_middle::mir::TerminatorKind::*;
-    use stable_mir::mir::Terminator;
-    match &terminator.kind {
-        Goto { target } => Terminator::Goto { target: target.as_usize() },
-        SwitchInt { discr, targets } => Terminator::SwitchInt {
-            discr: rustc_op_to_op(discr),
-            targets: targets
-                .iter()
-                .map(|(value, target)| stable_mir::mir::SwitchTarget {
-                    value,
-                    target: target.as_usize(),
-                })
-                .collect(),
-            otherwise: targets.otherwise().as_usize(),
-        },
-        Resume => Terminator::Resume,
-        Terminate => Terminator::Abort,
-        Return => Terminator::Return,
-        Unreachable => Terminator::Unreachable,
-        Drop { place, target, unwind, replace: _ } => Terminator::Drop {
-            place: rustc_place_to_place(place),
-            target: target.as_usize(),
-            unwind: rustc_unwind_to_unwind(unwind),
-        },
-        Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => {
-            Terminator::Call {
-                func: rustc_op_to_op(func),
-                args: args.iter().map(|arg| rustc_op_to_op(arg)).collect(),
-                destination: rustc_place_to_place(destination),
-                target: target.map(|t| t.as_usize()),
-                unwind: rustc_unwind_to_unwind(unwind),
-            }
-        }
-        Assert { cond, expected, msg, target, unwind } => Terminator::Assert {
-            cond: rustc_op_to_op(cond),
-            expected: *expected,
-            msg: rustc_assert_msg_to_msg(msg),
-            target: target.as_usize(),
-            unwind: rustc_unwind_to_unwind(unwind),
-        },
-        InlineAsm { template, operands, options, line_spans, destination, unwind } => {
-            Terminator::InlineAsm {
-                template: format!("{:?}", template),
-                operands: operands
+impl<'tcx> Stable for mir::Terminator<'tcx> {
+    type T = stable_mir::mir::Terminator;
+    fn stable(&self) -> Self::T {
+        use rustc_middle::mir::TerminatorKind::*;
+        use stable_mir::mir::Terminator;
+        match &self.kind {
+            Goto { target } => Terminator::Goto { target: target.as_usize() },
+            SwitchInt { discr, targets } => Terminator::SwitchInt {
+                discr: discr.stable(),
+                targets: targets
                     .iter()
-                    .map(|operand| rustc_inline_asm_operand_to_inline_asm_operand(operand))
+                    .map(|(value, target)| stable_mir::mir::SwitchTarget {
+                        value,
+                        target: target.as_usize(),
+                    })
                     .collect(),
-                options: format!("{:?}", options),
-                line_spans: format!("{:?}", line_spans),
-                destination: destination.map(|d| d.as_usize()),
-                unwind: rustc_unwind_to_unwind(unwind),
+                otherwise: targets.otherwise().as_usize(),
+            },
+            Resume => Terminator::Resume,
+            Terminate => Terminator::Abort,
+            Return => Terminator::Return,
+            Unreachable => Terminator::Unreachable,
+            Drop { place, target, unwind, replace: _ } => Terminator::Drop {
+                place: place.stable(),
+                target: target.as_usize(),
+                unwind: unwind.stable(),
+            },
+            Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => {
+                Terminator::Call {
+                    func: func.stable(),
+                    args: args.iter().map(|arg| arg.stable()).collect(),
+                    destination: destination.stable(),
+                    target: target.map(|t| t.as_usize()),
+                    unwind: unwind.stable(),
+                }
+            }
+            Assert { cond, expected, msg, target, unwind } => Terminator::Assert {
+                cond: cond.stable(),
+                expected: *expected,
+                msg: rustc_assert_msg_to_msg(msg),
+                target: target.as_usize(),
+                unwind: unwind.stable(),
+            },
+            InlineAsm { template, operands, options, line_spans, destination, unwind } => {
+                Terminator::InlineAsm {
+                    template: format!("{:?}", template),
+                    operands: operands.iter().map(|operand| operand.stable()).collect(),
+                    options: format!("{:?}", options),
+                    line_spans: format!("{:?}", line_spans),
+                    destination: destination.map(|d| d.as_usize()),
+                    unwind: unwind.stable(),
+                }
             }
+            Yield { .. } | GeneratorDrop | FalseEdge { .. } | FalseUnwind { .. } => unreachable!(),
         }
-        Yield { .. } | GeneratorDrop | FalseEdge { .. } | FalseUnwind { .. } => unreachable!(),
     }
 }
diff --git a/compiler/rustc_target/src/spec/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/loongarch64_unknown_none_softfloat.rs
index 93df4221e61..f444a7f24bb 100644
--- a/compiler/rustc_target/src/spec/loongarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/loongarch64_unknown_none_softfloat.rs
@@ -3,7 +3,7 @@ use super::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
-        llvm_target: "loongarch64-unknown-none-softfloat".into(),
+        llvm_target: "loongarch64-unknown-none".into(),
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
         arch: "loongarch64".into(),
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 2c793ea33dc..190a78f6a8e 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -23,7 +23,7 @@ use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 use std::fmt::Debug;
@@ -170,8 +170,8 @@ fn overlap<'tcx>(
     overlap_mode: OverlapMode,
 ) -> Option<OverlapResult<'tcx>> {
     if overlap_mode.use_negative_impl() {
-        if negative_impl(tcx, impl1_def_id, impl2_def_id)
-            || negative_impl(tcx, impl2_def_id, impl1_def_id)
+        if impl_intersection_has_negative_obligation(tcx, impl1_def_id, impl2_def_id)
+            || impl_intersection_has_negative_obligation(tcx, impl2_def_id, impl1_def_id)
         {
             return None;
         }
@@ -198,13 +198,21 @@ fn overlap<'tcx>(
     let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
     let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
 
-    let obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
+    // Equate the headers to find their intersection (the general type, with infer vars,
+    // that may apply both impls).
+    let equate_obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
     debug!("overlap: unification check succeeded");
 
-    if overlap_mode.use_implicit_negative() {
-        if implicit_negative(selcx, param_env, &impl1_header, impl2_header, obligations) {
-            return None;
-        }
+    if overlap_mode.use_implicit_negative()
+        && impl_intersection_has_impossible_obligation(
+            selcx,
+            param_env,
+            &impl1_header,
+            impl2_header,
+            equate_obligations,
+        )
+    {
+        return None;
     }
 
     // We toggle the `leak_check` by using `skip_leak_check` when constructing the
@@ -250,52 +258,38 @@ fn equate_impl_headers<'tcx>(
     result.map(|infer_ok| infer_ok.obligations).ok()
 }
 
-/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
-/// where-clauses) If so, return false, otherwise return true, they are disjoint.
-fn implicit_negative<'cx, 'tcx>(
+/// Check if both impls can be satisfied by a common type by considering whether
+/// any of either impl's obligations is not known to hold.
+///
+/// For example, given these two impls:
+///     `impl From<MyLocalType> for Box<dyn Error>` (in my crate)
+///     `impl<E> From<E> for Box<dyn Error> where E: Error` (in libstd)
+///
+/// After replacing both impl headers with inference vars (which happens before
+/// this function is called), we get:
+///     `Box<dyn Error>: From<MyLocalType>`
+///     `Box<dyn Error>: From<?E>`
+///
+/// This gives us `?E = MyLocalType`. We then certainly know that `MyLocalType: Error`
+/// never holds in intercrate mode since a local impl does not exist, and a
+/// downstream impl cannot be added -- therefore can consider the intersection
+/// of the two impls above to be empty.
+///
+/// Importantly, this works even if there isn't a `impl !Error for MyLocalType`.
+fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     impl1_header: &ty::ImplHeader<'tcx>,
     impl2_header: ty::ImplHeader<'tcx>,
     obligations: PredicateObligations<'tcx>,
 ) -> bool {
-    // There's no overlap if obligations are unsatisfiable or if the obligation negated is
-    // satisfied.
-    //
-    // For example, given these two impl headers:
-    //
-    // `impl<'a> From<&'a str> for Box<dyn Error>`
-    // `impl<E> From<E> for Box<dyn Error> where E: Error`
-    //
-    // So we have:
-    //
-    // `Box<dyn Error>: From<&'?a str>`
-    // `Box<dyn Error>: From<?E>`
-    //
-    // After equating the two headers:
-    //
-    // `Box<dyn Error> = Box<dyn Error>`
-    // So, `?E = &'?a str` and then given the where clause `&'?a str: Error`.
-    //
-    // If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't
-    // hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because
-    // at some point an impl for `&'?a str: Error` could be added.
-    debug!(
-        "implicit_negative(impl1_header={:?}, impl2_header={:?}, obligations={:?})",
-        impl1_header, impl2_header, obligations
-    );
     let infcx = selcx.infcx;
-    let opt_failing_obligation = impl1_header
-        .predicates
-        .iter()
-        .copied()
-        .chain(impl2_header.predicates)
-        .map(|p| infcx.resolve_vars_if_possible(p))
-        .map(|p| Obligation {
-            cause: ObligationCause::dummy(),
-            param_env,
-            recursion_depth: 0,
-            predicate: p,
+
+    let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates]
+        .into_iter()
+        .flatten()
+        .map(|&predicate| {
+            Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate)
         })
         .chain(obligations)
         .find(|o| !selcx.predicate_may_hold_fatal(o));
@@ -308,9 +302,27 @@ fn implicit_negative<'cx, 'tcx>(
     }
 }
 
-/// Given impl1 and impl2 check if both impls are never satisfied by a common type (including
-/// where-clauses) If so, return true, they are disjoint and false otherwise.
-fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> bool {
+/// Check if both impls can be satisfied by a common type by considering whether
+/// any of first impl's obligations is known not to hold *via a negative predicate*.
+///
+/// For example, given these two impls:
+///     `struct MyCustomBox<T: ?Sized>(Box<T>);`
+///     `impl From<&str> for MyCustomBox<dyn Error>` (in my crate)
+///     `impl<E> From<E> for MyCustomBox<dyn Error> where E: Error` (in my crate)
+///
+/// After replacing the second impl's header with inference vars, we get:
+///     `MyCustomBox<dyn Error>: From<&str>`
+///     `MyCustomBox<dyn Error>: From<?E>`
+///
+/// This gives us `?E = &str`. We then try to prove the first impl's predicates
+/// after negating, giving us `&str: !Error`. This is a negative impl provided by
+/// libstd, and therefore we can guarantee for certain that libstd will never add
+/// a positive impl for `&str: Error` (without it being a breaking change).
+fn impl_intersection_has_negative_obligation(
+    tcx: TyCtxt<'_>,
+    impl1_def_id: DefId,
+    impl2_def_id: DefId,
+) -> bool {
     debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
@@ -336,57 +348,45 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b
     // Attempt to prove that impl2 applies, given all of the above.
     let selcx = &mut SelectionContext::new(&infcx);
     let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
-    let (subject2, obligations) =
+    let (subject2, normalization_obligations) =
         impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs, |_, _| {
             ObligationCause::dummy()
         });
 
-    !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
-}
-
-fn equate<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    impl_env: ty::ParamEnv<'tcx>,
-    subject1: ImplSubject<'tcx>,
-    subject2: ImplSubject<'tcx>,
-    obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
-    body_def_id: DefId,
-) -> bool {
-    // do the impls unify? If not, not disjoint.
-    let Ok(InferOk { obligations: more_obligations, .. }) =
+    // do the impls unify? If not, then it's not currently possible to prove any
+    // obligations about their intersection.
+    let Ok(InferOk { obligations: equate_obligations, .. }) =
         infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No,subject1, subject2)
     else {
         debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
-        return true;
+        return false;
     };
 
-    let opt_failing_obligation = obligations
-        .into_iter()
-        .chain(more_obligations)
-        .find(|o| negative_impl_exists(infcx, o, body_def_id));
-
-    if let Some(failing_obligation) = opt_failing_obligation {
-        debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
-        false
-    } else {
-        true
+    for obligation in normalization_obligations.into_iter().chain(equate_obligations) {
+        if negative_impl_exists(&infcx, &obligation, impl1_def_id) {
+            debug!("overlap: obligation unsatisfiable {:?}", obligation);
+            return true;
+        }
     }
+
+    false
 }
 
-/// Try to prove that a negative impl exist for the given obligation and its super predicates.
+/// Try to prove that a negative impl exist for the obligation or its supertraits.
+///
+/// If such a negative impl exists, then the obligation definitely must not hold
+/// due to coherence, even if it's not necessarily "knowable" in this crate. Any
+/// valid impl downstream would not be able to exist due to the overlapping
+/// negative impl.
 #[instrument(level = "debug", skip(infcx))]
 fn negative_impl_exists<'tcx>(
     infcx: &InferCtxt<'tcx>,
     o: &PredicateObligation<'tcx>,
     body_def_id: DefId,
 ) -> bool {
-    if resolve_negative_obligation(infcx.fork(), o, body_def_id) {
-        return true;
-    }
-
     // Try to prove a negative obligation exists for super predicates
     for pred in util::elaborate(infcx.tcx, iter::once(o.predicate)) {
-        if resolve_negative_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) {
+        if prove_negated_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) {
             return true;
         }
     }
@@ -395,7 +395,7 @@ fn negative_impl_exists<'tcx>(
 }
 
 #[instrument(level = "debug", skip(infcx))]
-fn resolve_negative_obligation<'tcx>(
+fn prove_negated_obligation<'tcx>(
     infcx: InferCtxt<'tcx>,
     o: &PredicateObligation<'tcx>,
     body_def_id: DefId,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 25e5b5e17de..5acd7b573dd 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -365,7 +365,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
 
                     if !candidate_set.ambiguous && no_candidates_apply {
-                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                        let trait_ref = self.infcx.resolve_vars_if_possible(
+                            stack.obligation.predicate.skip_binder().trait_ref,
+                        );
                         if !trait_ref.references_error() {
                             let self_ty = trait_ref.self_ty();
                             let (trait_desc, self_desc) = with_no_trimmed_paths!({
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index 413b31282f7..75aa0c2b2a2 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.16.6
\ No newline at end of file
+0.16.7
\ No newline at end of file
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index b26480f668b..af1bc05ddb2 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -201,8 +201,8 @@ async function main(argv) {
     try {
         // This is more convenient that setting fields one by one.
         const args = [
-            "--variable", "DOC_PATH", opts["doc_folder"], "--enable-fail-on-js-error",
-            "--allow-file-access-from-files",
+            "--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"),
+            "--enable-fail-on-js-error", "--allow-file-access-from-files",
         ];
         if (opts["debug"]) {
             debug = true;
diff --git a/tests/rustdoc-gui/shortcuts.goml b/tests/rustdoc-gui/shortcuts.goml
index 667df89ec9b..2c61ee5428b 100644
--- a/tests/rustdoc-gui/shortcuts.goml
+++ b/tests/rustdoc-gui/shortcuts.goml
@@ -13,7 +13,7 @@ press-key: "Escape"
 assert-css: ("#help-button .popover", {"display": "none"})
 // Checking doc collapse and expand.
 // It should be displaying a "-":
-assert-text: ("#toggle-all-docs", "[\u2212]")
+assert-text: ("#toggle-all-docs", "[−]")
 press-key: "-"
 wait-for-text: ("#toggle-all-docs", "[+]")
 assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
@@ -23,9 +23,9 @@ assert-text: ("#toggle-all-docs", "[+]")
 assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
 // Expanding now.
 press-key: "+"
-wait-for-text: ("#toggle-all-docs", "[\u2212]")
+wait-for-text: ("#toggle-all-docs", "[−]")
 assert-attribute: ("#toggle-all-docs", {"class": ""})
 // Pressing it again shouldn't do anything.
 press-key: "+"
-assert-text: ("#toggle-all-docs", "[\u2212]")
+assert-text: ("#toggle-all-docs", "[−]")
 assert-attribute: ("#toggle-all-docs", {"class": ""})
diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml
index d5dd511b1d3..f8f73398d9b 100644
--- a/tests/rustdoc-gui/source-code-page.goml
+++ b/tests/rustdoc-gui/source-code-page.goml
@@ -64,23 +64,23 @@ call-function: ("check-colors", {
 compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
 // Check the `href` property so that users can treat anchors as links.
 assert-property: (".src-line-numbers > a:nth-child(1)", {
-    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#1"
-})
+    "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#1"
+}, ENDS_WITH)
 assert-property: (".src-line-numbers > a:nth-child(2)", {
-    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#2"
-})
+    "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#2"
+}, ENDS_WITH)
 assert-property: (".src-line-numbers > a:nth-child(3)", {
-    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#3"
-})
+    "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#3"
+}, ENDS_WITH)
 assert-property: (".src-line-numbers > a:nth-child(4)", {
-    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#4"
-})
+    "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#4"
+}, ENDS_WITH)
 assert-property: (".src-line-numbers > a:nth-child(5)", {
-    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#5"
-})
+    "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#5"
+}, ENDS_WITH)
 assert-property: (".src-line-numbers > a:nth-child(6)", {
-    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#6"
-})
+    "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#6"
+}, ENDS_WITH)
 
 // Assert that the line numbers text is aligned to the right.
 assert-css: (".src-line-numbers", {"text-align": "right"})
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr
new file mode 100644
index 00000000000..f604ada6ac7
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr
@@ -0,0 +1,21 @@
+error[E0053]: method `early` has an incompatible type for trait
+  --> $DIR/method-signature-matches.rs:58:27
+   |
+LL |     fn early<'late, T>(_: &'late ()) {}
+   |                     -     ^^^^^^^^^
+   |                     |     |
+   |                     |     expected type parameter `T`, found `()`
+   |                     |     help: change the parameter type to match the trait: `&'early T`
+   |                     this type parameter
+   |
+note: type in trait
+  --> $DIR/method-signature-matches.rs:53:28
+   |
+LL |     fn early<'early, T>(x: &'early T) -> impl Sized;
+   |                            ^^^^^^^^^
+   = note: expected signature `fn(&'early T)`
+              found signature `fn(&())`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr
new file mode 100644
index 00000000000..d3183b92e84
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr
@@ -0,0 +1,20 @@
+error[E0053]: method `owo` has an incompatible type for trait
+  --> $DIR/method-signature-matches.rs:14:15
+   |
+LL |     fn owo(_: u8) {}
+   |               ^^
+   |               |
+   |               expected `()`, found `u8`
+   |               help: change the parameter type to match the trait: `()`
+   |
+note: type in trait
+  --> $DIR/method-signature-matches.rs:9:15
+   |
+LL |     fn owo(x: ()) -> impl Sized;
+   |               ^^
+   = note: expected signature `fn(())`
+              found signature `fn(u8)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr
new file mode 100644
index 00000000000..80fda1c9fe1
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr
@@ -0,0 +1,20 @@
+error[E0053]: method `owo` has an incompatible type for trait
+  --> $DIR/method-signature-matches.rs:25:21
+   |
+LL |     async fn owo(_: u8) {}
+   |                     ^^
+   |                     |
+   |                     expected `()`, found `u8`
+   |                     help: change the parameter type to match the trait: `()`
+   |
+note: type in trait
+  --> $DIR/method-signature-matches.rs:20:21
+   |
+LL |     async fn owo(x: ()) {}
+   |                     ^^
+   = note: expected signature `fn(()) -> _`
+              found signature `fn(u8) -> _`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.rs b/tests/ui/impl-trait/in-trait/method-signature-matches.rs
index c848ee3f643..294f93b30d0 100644
--- a/tests/ui/impl-trait/in-trait/method-signature-matches.rs
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.rs
@@ -1,51 +1,62 @@
 // edition: 2021
+// revisions: mismatch mismatch_async too_many too_few lt
 
 #![feature(return_position_impl_trait_in_trait, async_fn_in_trait)]
 #![allow(incomplete_features)]
 
+#[cfg(mismatch)]
 trait Uwu {
     fn owo(x: ()) -> impl Sized;
 }
 
+#[cfg(mismatch)]
 impl Uwu for () {
     fn owo(_: u8) {}
-    //~^ ERROR method `owo` has an incompatible type for trait
+    //[mismatch]~^ ERROR method `owo` has an incompatible type for trait
 }
 
+#[cfg(mismatch_async)]
 trait AsyncUwu {
     async fn owo(x: ()) {}
 }
 
+#[cfg(mismatch_async)]
 impl AsyncUwu for () {
     async fn owo(_: u8) {}
-    //~^ ERROR method `owo` has an incompatible type for trait
+    //[mismatch_async]~^ ERROR method `owo` has an incompatible type for trait
 }
 
+#[cfg(too_many)]
 trait TooMuch {
     fn calm_down_please() -> impl Sized;
 }
 
+#[cfg(too_many)]
 impl TooMuch for () {
     fn calm_down_please(_: (), _: (), _: ()) {}
-    //~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
+    //[too_many]~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
 }
 
+#[cfg(too_few)]
 trait TooLittle {
     fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
 }
 
+#[cfg(too_few)]
 impl TooLittle for () {
     fn come_on_a_little_more_effort() {}
-    //~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
+    //[too_few]~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
 }
 
+#[cfg(lt)]
 trait Lifetimes {
     fn early<'early, T>(x: &'early T) -> impl Sized;
 }
 
+#[cfg(lt)]
 impl Lifetimes for () {
     fn early<'late, T>(_: &'late ()) {}
-    //~^ ERROR method `early` has an incompatible type for trait
+    //[lt]~^ ERROR method `early` has an incompatible type for trait
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.stderr
deleted file mode 100644
index 3ec62020e6c..00000000000
--- a/tests/ui/impl-trait/in-trait/method-signature-matches.stderr
+++ /dev/null
@@ -1,74 +0,0 @@
-error[E0053]: method `owo` has an incompatible type for trait
-  --> $DIR/method-signature-matches.rs:11:15
-   |
-LL |     fn owo(_: u8) {}
-   |               ^^
-   |               |
-   |               expected `()`, found `u8`
-   |               help: change the parameter type to match the trait: `()`
-   |
-note: type in trait
-  --> $DIR/method-signature-matches.rs:7:15
-   |
-LL |     fn owo(x: ()) -> impl Sized;
-   |               ^^
-   = note: expected signature `fn(())`
-              found signature `fn(u8)`
-
-error[E0053]: method `owo` has an incompatible type for trait
-  --> $DIR/method-signature-matches.rs:20:21
-   |
-LL |     async fn owo(_: u8) {}
-   |                     ^^
-   |                     |
-   |                     expected `()`, found `u8`
-   |                     help: change the parameter type to match the trait: `()`
-   |
-note: type in trait
-  --> $DIR/method-signature-matches.rs:16:21
-   |
-LL |     async fn owo(x: ()) {}
-   |                     ^^
-   = note: expected signature `fn(()) -> _`
-              found signature `fn(u8) -> _`
-
-error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
-  --> $DIR/method-signature-matches.rs:29:28
-   |
-LL |     fn calm_down_please() -> impl Sized;
-   |     ------------------------------------ trait requires 0 parameters
-...
-LL |     fn calm_down_please(_: (), _: (), _: ()) {}
-   |                            ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3
-
-error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
-  --> $DIR/method-signature-matches.rs:38:5
-   |
-LL |     fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
-   |                                        ---------------- trait requires 3 parameters
-...
-LL |     fn come_on_a_little_more_effort() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0
-
-error[E0053]: method `early` has an incompatible type for trait
-  --> $DIR/method-signature-matches.rs:47:27
-   |
-LL |     fn early<'late, T>(_: &'late ()) {}
-   |                     -     ^^^^^^^^^
-   |                     |     |
-   |                     |     expected type parameter `T`, found `()`
-   |                     |     help: change the parameter type to match the trait: `&'early T`
-   |                     this type parameter
-   |
-note: type in trait
-  --> $DIR/method-signature-matches.rs:43:28
-   |
-LL |     fn early<'early, T>(x: &'early T) -> impl Sized;
-   |                            ^^^^^^^^^
-   = note: expected signature `fn(&'early T)`
-              found signature `fn(&())`
-
-error: aborting due to 5 previous errors
-
-Some errors have detailed explanations: E0050, E0053.
-For more information about an error, try `rustc --explain E0050`.
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr
new file mode 100644
index 00000000000..24bcfeb748f
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr
@@ -0,0 +1,12 @@
+error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
+  --> $DIR/method-signature-matches.rs:47:5
+   |
+LL |     fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
+   |                                        ---------------- trait requires 3 parameters
+...
+LL |     fn come_on_a_little_more_effort() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0050`.
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr
new file mode 100644
index 00000000000..616cbd2905c
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr
@@ -0,0 +1,12 @@
+error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
+  --> $DIR/method-signature-matches.rs:36:28
+   |
+LL |     fn calm_down_please() -> impl Sized;
+   |     ------------------------------------ trait requires 0 parameters
+...
+LL |     fn calm_down_please(_: (), _: (), _: ()) {}
+   |                            ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0050`.
diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr b/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr
new file mode 100644
index 00000000000..bf088ae8b25
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained-lt.rs:10:6
+   |
+LL | impl<'a, T> Foo for T {
+   |      ^^ unconstrained lifetime parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr b/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr
new file mode 100644
index 00000000000..bf088ae8b25
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained-lt.rs:10:6
+   |
+LL | impl<'a, T> Foo for T {
+   |      ^^ unconstrained lifetime parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.rs b/tests/ui/impl-trait/in-trait/unconstrained-lt.rs
new file mode 100644
index 00000000000..f966be43a6e
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.rs
@@ -0,0 +1,16 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
+#![feature(return_position_impl_trait_in_trait)]
+
+trait Foo {
+    fn test() -> impl Sized;
+}
+
+impl<'a, T> Foo for T {
+    //~^ ERROR the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
+
+    fn test() -> &'a () { &() }
+}
+
+fn main() {}
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.fixed b/tests/ui/rust-2018/edition-lint-infer-outlives.fixed
index 868bdf2e068..5058d61b588 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives.fixed
+++ b/tests/ui/rust-2018/edition-lint-infer-outlives.fixed
@@ -801,4 +801,10 @@ where
     yoo: &'a U
 }
 
+// https://github.com/rust-lang/rust/issues/105150
+struct InferredWhereBoundWithInlineBound<'a, T: ?Sized>
+{
+    data: &'a T,
+}
+
 fn main() {}
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.rs b/tests/ui/rust-2018/edition-lint-infer-outlives.rs
index 75783764ad6..3f63cb8e900 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives.rs
+++ b/tests/ui/rust-2018/edition-lint-infer-outlives.rs
@@ -801,4 +801,12 @@ where
     yoo: &'a U
 }
 
+// https://github.com/rust-lang/rust/issues/105150
+struct InferredWhereBoundWithInlineBound<'a, T: ?Sized>
+//~^ ERROR outlives requirements can be inferred
+    where T: 'a,
+{
+    data: &'a T,
+}
+
 fn main() {}
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.stderr b/tests/ui/rust-2018/edition-lint-infer-outlives.stderr
index e655fb4842c..dbf301fd8a1 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives.stderr
+++ b/tests/ui/rust-2018/edition-lint-infer-outlives.stderr
@@ -11,6 +11,15 @@ LL | #![deny(explicit_outlives_requirements)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives.rs:805:56
+   |
+LL |   struct InferredWhereBoundWithInlineBound<'a, T: ?Sized>
+   |  ________________________________________________________^
+LL | |
+LL | |     where T: 'a,
+   | |________________^ help: remove this bound
+
+error: outlives requirements can be inferred
   --> $DIR/edition-lint-infer-outlives.rs:26:31
    |
 LL |     struct TeeOutlivesAy<'a, T: 'a> {
@@ -922,5 +931,5 @@ error: outlives requirements can be inferred
 LL |     union BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug {
    |                                                            ^^^^^^^^ help: remove this bound
 
-error: aborting due to 153 previous errors
+error: aborting due to 154 previous errors