about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs344
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs30
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs5
7 files changed, 349 insertions, 66 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 bbf36fef1dd..fb67f2fd223 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -5,7 +5,7 @@ use std::iter;
 use hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
-use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
+use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::VisitorExt;
 use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};
@@ -14,10 +14,10 @@ use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{
     self, BottomUpFolder, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder,
-    TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast,
+    TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
 };
 use rustc_middle::{bug, span_bug};
-use rustc_span::Span;
+use rustc_span::{DUMMY_SP, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
@@ -1137,65 +1137,319 @@ fn check_region_bounds_on_impl_item<'tcx>(
     // but found 0" it's confusing, because it looks like there
     // are zero. Since I don't quite know how to phrase things at
     // the moment, give a kind of vague error message.
-    if trait_params != impl_params {
-        let span = tcx
-            .hir_get_generics(impl_m.def_id.expect_local())
-            .expect("expected impl item to have generics or else we can't compare them")
-            .span;
-
-        let mut generics_span = None;
-        let mut bounds_span = vec![];
-        let mut where_span = None;
-        if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id)
-            && let Some(trait_generics) = trait_node.generics()
-        {
-            generics_span = Some(trait_generics.span);
-            // FIXME: we could potentially look at the impl's bounds to not point at bounds that
-            // *are* present in the impl.
-            for p in trait_generics.predicates {
-                if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind {
-                    for b in pred.bounds {
+    if trait_params == impl_params {
+        return Ok(());
+    }
+
+    if !delay && let Some(guar) = check_region_late_boundedness(tcx, impl_m, trait_m) {
+        return Err(guar);
+    }
+
+    let span = tcx
+        .hir_get_generics(impl_m.def_id.expect_local())
+        .expect("expected impl item to have generics or else we can't compare them")
+        .span;
+
+    let mut generics_span = None;
+    let mut bounds_span = vec![];
+    let mut where_span = None;
+
+    if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id)
+        && let Some(trait_generics) = trait_node.generics()
+    {
+        generics_span = Some(trait_generics.span);
+        // FIXME: we could potentially look at the impl's bounds to not point at bounds that
+        // *are* present in the impl.
+        for p in trait_generics.predicates {
+            match p.kind {
+                hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
+                    bounds,
+                    ..
+                })
+                | hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
+                    bounds,
+                    ..
+                }) => {
+                    for b in *bounds {
                         if let hir::GenericBound::Outlives(lt) = b {
                             bounds_span.push(lt.ident.span);
                         }
                     }
                 }
+                _ => {}
             }
-            if let Some(impl_node) = tcx.hir_get_if_local(impl_m.def_id)
-                && let Some(impl_generics) = impl_node.generics()
-            {
-                let mut impl_bounds = 0;
-                for p in impl_generics.predicates {
-                    if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind {
-                        for b in pred.bounds {
+        }
+        if let Some(impl_node) = tcx.hir_get_if_local(impl_m.def_id)
+            && let Some(impl_generics) = impl_node.generics()
+        {
+            let mut impl_bounds = 0;
+            for p in impl_generics.predicates {
+                match p.kind {
+                    hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
+                        bounds,
+                        ..
+                    })
+                    | hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
+                        bounds,
+                        ..
+                    }) => {
+                        for b in *bounds {
                             if let hir::GenericBound::Outlives(_) = b {
                                 impl_bounds += 1;
                             }
                         }
                     }
+                    _ => {}
+                }
+            }
+            if impl_bounds == bounds_span.len() {
+                bounds_span = vec![];
+            } else if impl_generics.has_where_clause_predicates {
+                where_span = Some(impl_generics.where_clause_span);
+            }
+        }
+    }
+
+    let reported = tcx
+        .dcx()
+        .create_err(LifetimesOrBoundsMismatchOnTrait {
+            span,
+            item_kind: impl_m.descr(),
+            ident: impl_m.ident(tcx),
+            generics_span,
+            bounds_span,
+            where_span,
+        })
+        .emit_unless(delay);
+
+    Err(reported)
+}
+
+#[allow(unused)]
+enum LateEarlyMismatch<'tcx> {
+    EarlyInImpl(DefId, DefId, ty::Region<'tcx>),
+    LateInImpl(DefId, DefId, ty::Region<'tcx>),
+}
+
+fn check_region_late_boundedness<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: ty::AssocItem,
+    trait_m: ty::AssocItem,
+) -> Option<ErrorGuaranteed> {
+    if !impl_m.is_fn() {
+        return None;
+    }
+
+    let (infcx, param_env) = tcx
+        .infer_ctxt()
+        .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, impl_m.def_id));
+
+    let impl_m_args = infcx.fresh_args_for_item(DUMMY_SP, impl_m.def_id);
+    let impl_m_sig = tcx.fn_sig(impl_m.def_id).instantiate(tcx, impl_m_args);
+    let impl_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, impl_m_sig);
+
+    let trait_m_args = infcx.fresh_args_for_item(DUMMY_SP, trait_m.def_id);
+    let trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_args);
+    let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_m_sig);
+
+    let ocx = ObligationCtxt::new(&infcx);
+
+    // Equate the signatures so that we can infer whether a late-bound param was present where
+    // an early-bound param was expected, since we replace the late-bound lifetimes with
+    // `ReLateParam`, and early-bound lifetimes with infer vars, so the early-bound args will
+    // resolve to `ReLateParam` if there is a mismatch.
+    let Ok(()) = ocx.eq(
+        &ObligationCause::dummy(),
+        param_env,
+        ty::Binder::dummy(trait_m_sig),
+        ty::Binder::dummy(impl_m_sig),
+    ) else {
+        return None;
+    };
+
+    let errors = ocx.select_where_possible();
+    if !errors.is_empty() {
+        return None;
+    }
+
+    let mut mismatched = vec![];
+
+    let impl_generics = tcx.generics_of(impl_m.def_id);
+    for (id_arg, arg) in
+        std::iter::zip(ty::GenericArgs::identity_for_item(tcx, impl_m.def_id), impl_m_args)
+    {
+        if let ty::GenericArgKind::Lifetime(r) = arg.unpack()
+            && let ty::ReVar(vid) = r.kind()
+            && let r = infcx
+                .inner
+                .borrow_mut()
+                .unwrap_region_constraints()
+                .opportunistic_resolve_var(tcx, vid)
+            && let ty::ReLateParam(ty::LateParamRegion {
+                kind: ty::LateParamRegionKind::Named(trait_param_def_id, _),
+                ..
+            }) = r.kind()
+            && let ty::ReEarlyParam(ebr) = id_arg.expect_region().kind()
+        {
+            mismatched.push(LateEarlyMismatch::EarlyInImpl(
+                impl_generics.region_param(ebr, tcx).def_id,
+                trait_param_def_id,
+                id_arg.expect_region(),
+            ));
+        }
+    }
+
+    let trait_generics = tcx.generics_of(trait_m.def_id);
+    for (id_arg, arg) in
+        std::iter::zip(ty::GenericArgs::identity_for_item(tcx, trait_m.def_id), trait_m_args)
+    {
+        if let ty::GenericArgKind::Lifetime(r) = arg.unpack()
+            && let ty::ReVar(vid) = r.kind()
+            && let r = infcx
+                .inner
+                .borrow_mut()
+                .unwrap_region_constraints()
+                .opportunistic_resolve_var(tcx, vid)
+            && let ty::ReLateParam(ty::LateParamRegion {
+                kind: ty::LateParamRegionKind::Named(impl_param_def_id, _),
+                ..
+            }) = r.kind()
+            && let ty::ReEarlyParam(ebr) = id_arg.expect_region().kind()
+        {
+            mismatched.push(LateEarlyMismatch::LateInImpl(
+                impl_param_def_id,
+                trait_generics.region_param(ebr, tcx).def_id,
+                id_arg.expect_region(),
+            ));
+        }
+    }
+
+    if mismatched.is_empty() {
+        return None;
+    }
+
+    let spans: Vec<_> = mismatched
+        .iter()
+        .map(|param| {
+            let (LateEarlyMismatch::EarlyInImpl(impl_param_def_id, ..)
+            | LateEarlyMismatch::LateInImpl(impl_param_def_id, ..)) = param;
+            tcx.def_span(impl_param_def_id)
+        })
+        .collect();
+
+    let mut diag = tcx
+        .dcx()
+        .struct_span_err(spans, "lifetime parameters do not match the trait definition")
+        .with_note("lifetime parameters differ in whether they are early- or late-bound")
+        .with_code(E0195);
+    for mismatch in mismatched {
+        match mismatch {
+            LateEarlyMismatch::EarlyInImpl(
+                impl_param_def_id,
+                trait_param_def_id,
+                early_bound_region,
+            ) => {
+                let mut multispan = MultiSpan::from_spans(vec![
+                    tcx.def_span(impl_param_def_id),
+                    tcx.def_span(trait_param_def_id),
+                ]);
+                multispan
+                    .push_span_label(tcx.def_span(tcx.parent(impl_m.def_id)), "in this impl...");
+                multispan
+                    .push_span_label(tcx.def_span(tcx.parent(trait_m.def_id)), "in this trait...");
+                multispan.push_span_label(
+                    tcx.def_span(impl_param_def_id),
+                    format!("`{}` is early-bound", tcx.item_name(impl_param_def_id)),
+                );
+                multispan.push_span_label(
+                    tcx.def_span(trait_param_def_id),
+                    format!("`{}` is late-bound", tcx.item_name(trait_param_def_id)),
+                );
+                if let Some(span) =
+                    find_region_in_predicates(tcx, impl_m.def_id, early_bound_region)
+                {
+                    multispan.push_span_label(
+                        span,
+                        format!(
+                            "this lifetime bound makes `{}` early-bound",
+                            tcx.item_name(impl_param_def_id)
+                        ),
+                    );
                 }
-                if impl_bounds == bounds_span.len() {
-                    bounds_span = vec![];
-                } else if impl_generics.has_where_clause_predicates {
-                    where_span = Some(impl_generics.where_clause_span);
+                diag.span_note(
+                    multispan,
+                    format!(
+                        "`{}` differs between the trait and impl",
+                        tcx.item_name(impl_param_def_id)
+                    ),
+                );
+            }
+            LateEarlyMismatch::LateInImpl(
+                impl_param_def_id,
+                trait_param_def_id,
+                early_bound_region,
+            ) => {
+                let mut multispan = MultiSpan::from_spans(vec![
+                    tcx.def_span(impl_param_def_id),
+                    tcx.def_span(trait_param_def_id),
+                ]);
+                multispan
+                    .push_span_label(tcx.def_span(tcx.parent(impl_m.def_id)), "in this impl...");
+                multispan
+                    .push_span_label(tcx.def_span(tcx.parent(trait_m.def_id)), "in this trait...");
+                multispan.push_span_label(
+                    tcx.def_span(impl_param_def_id),
+                    format!("`{}` is late-bound", tcx.item_name(impl_param_def_id)),
+                );
+                multispan.push_span_label(
+                    tcx.def_span(trait_param_def_id),
+                    format!("`{}` is early-bound", tcx.item_name(trait_param_def_id)),
+                );
+                if let Some(span) =
+                    find_region_in_predicates(tcx, trait_m.def_id, early_bound_region)
+                {
+                    multispan.push_span_label(
+                        span,
+                        format!(
+                            "this lifetime bound makes `{}` early-bound",
+                            tcx.item_name(trait_param_def_id)
+                        ),
+                    );
                 }
+                diag.span_note(
+                    multispan,
+                    format!(
+                        "`{}` differs between the trait and impl",
+                        tcx.item_name(impl_param_def_id)
+                    ),
+                );
             }
         }
-        let reported = tcx
-            .dcx()
-            .create_err(LifetimesOrBoundsMismatchOnTrait {
-                span,
-                item_kind: impl_m.descr(),
-                ident: impl_m.ident(tcx),
-                generics_span,
-                bounds_span,
-                where_span,
-            })
-            .emit_unless(delay);
-        return Err(reported);
     }
 
-    Ok(())
+    Some(diag.emit())
+}
+
+fn find_region_in_predicates<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    early_bound_region: ty::Region<'tcx>,
+) -> Option<Span> {
+    for (pred, span) in tcx.explicit_predicates_of(def_id).instantiate_identity(tcx) {
+        if pred.visit_with(&mut FindRegion(early_bound_region)).is_break() {
+            return Some(span);
+        }
+    }
+
+    struct FindRegion<'tcx>(ty::Region<'tcx>);
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindRegion<'tcx> {
+        type Result = ControlFlow<()>;
+        fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
+            if r == self.0 { ControlFlow::Break(()) } else { ControlFlow::Continue(()) }
+        }
+    }
+
+    None
 }
 
 #[instrument(level = "debug", skip(infcx))]
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 692784bf171..9fd158ad154 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -103,10 +103,18 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
         | sym::minnumf32
         | sym::minnumf64
         | sym::minnumf128
+        | sym::minimumf16
+        | sym::minimumf32
+        | sym::minimumf64
+        | sym::minimumf128
         | sym::maxnumf16
         | sym::maxnumf32
         | sym::maxnumf64
         | sym::maxnumf128
+        | sym::maximumf16
+        | sym::maximumf32
+        | sym::maximumf64
+        | sym::maximumf128
         | sym::rustc_peek
         | sym::type_name
         | sym::forget
@@ -374,11 +382,21 @@ pub(crate) fn check_intrinsic_type(
             sym::minnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
             sym::minnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
 
+            sym::minimumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
+            sym::minimumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::minimumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::minimumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
+
             sym::maxnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
             sym::maxnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::maxnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
             sym::maxnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
 
+            sym::maximumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
+            sym::maximumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::maximumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::maximumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
+
             sym::copysignf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
             sym::copysignf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::copysignf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index a89160785eb..709446d09cd 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -14,7 +14,7 @@ use rustc_ast::visit::walk_list;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::definitions::DisambiguatorState;
+use rustc_hir::definitions::{DefPathData, DisambiguatorState};
 use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
 use rustc_hir::{
     self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node,
@@ -1470,14 +1470,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             let mut captures = captures.borrow_mut();
             let remapped = *captures.entry(lifetime).or_insert_with(|| {
                 // `opaque_def_id` is unique to the `BoundVarContext` pass which is executed once
-                // per `resolve_bound_vars` query. This is the only location that creates nested
-                // lifetime inside a opaque type. `<opaque_def_id>::LifetimeNs(..)` is thus unique
+                // per `resolve_bound_vars` query. This is the only location that creates
+                // `OpaqueLifetime` paths. `<opaque_def_id>::OpaqueLifetime(..)` is thus unique
                 // to this query and duplicates within the query are handled by `self.disambiguator`.
                 let feed = self.tcx.create_def(
                     opaque_def_id,
-                    Some(ident.name),
-                    DefKind::LifetimeParam,
                     None,
+                    DefKind::LifetimeParam,
+                    Some(DefPathData::OpaqueLifetime(ident.name)),
                     &mut self.disambiguator,
                 );
                 feed.def_span(ident.span);
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 2b1661aaac8..152714b3407 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1327,7 +1327,7 @@ pub(crate) struct ImplForTyRequires {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_traits_with_defualt_impl, code = E0321)]
+#[diag(hir_analysis_traits_with_default_impl, code = E0321)]
 #[note]
 pub(crate) struct TraitsWithDefaultImpl<'a> {
     #[primary_span]
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index bf91eb1b8fd..4419d5dc7d6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -9,8 +9,8 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{AmbigArg, HirId};
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
-    TypeVisitor, Upcast,
+    self as ty, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt, TypeVisitor, Upcast,
 };
 use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
 use rustc_trait_selection::traits;
@@ -996,7 +996,7 @@ struct GenericParamAndBoundVarCollector<'a, 'tcx> {
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 'tcx> {
     type Result = ControlFlow<ErrorGuaranteed>;
 
-    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
+    fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
         &mut self,
         binder: &ty::Binder<'tcx, T>,
     ) -> Self::Result {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 88f74589204..f6e5149bd2b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -172,7 +172,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         let principal_trait = regular_traits.into_iter().next();
 
-        let mut needed_associated_types = vec![];
+        // A stable ordering of associated types from the principal trait and all its
+        // supertraits. We use this to ensure that different substitutions of a trait
+        // don't result in `dyn Trait` types with different projections lists, which
+        // can be unsound: <https://github.com/rust-lang/rust/pull/136458>.
+        // We achieve a stable ordering by walking over the unsubstituted principal
+        // trait ref.
+        let mut ordered_associated_types = vec![];
+
         if let Some((principal_trait, ref spans)) = principal_trait {
             let principal_trait = principal_trait.map_bound(|trait_pred| {
                 assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
@@ -197,16 +204,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         // FIXME(negative_bounds): Handle this correctly...
                         let trait_ref =
                             tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
-                        needed_associated_types.extend(
+                        ordered_associated_types.extend(
                             tcx.associated_items(pred.trait_ref.def_id)
                                 .in_definition_order()
                                 // We only care about associated types.
                                 .filter(|item| item.is_type())
                                 // No RPITITs -- they're not dyn-compatible for now.
                                 .filter(|item| !item.is_impl_trait_in_trait())
-                                // If the associated type has a `where Self: Sized` bound,
-                                // we do not need to constrain the associated type.
-                                .filter(|item| !tcx.generics_require_sized_self(item.def_id))
                                 .map(|item| (item.def_id, trait_ref)),
                         );
                     }
@@ -278,14 +282,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
+        // We compute the list of projection bounds taking the ordered associated types,
+        // and check if there was an entry in the collected `projection_bounds`. Those
+        // are computed by first taking the user-written associated types, then elaborating
+        // the principal trait ref, and only using those if there was no user-written.
+        // See note below about how we handle missing associated types with `Self: Sized`,
+        // which are not required to be provided, but are still used if they are provided.
         let mut missing_assoc_types = FxIndexSet::default();
-        let projection_bounds: Vec<_> = needed_associated_types
+        let projection_bounds: Vec<_> = ordered_associated_types
             .into_iter()
             .filter_map(|key| {
                 if let Some(assoc) = projection_bounds.get(&key) {
                     Some(*assoc)
                 } else {
-                    missing_assoc_types.insert(key);
+                    // If the associated type has a `where Self: Sized` bound, then
+                    // we do not need to provide the associated type. This results in
+                    // a `dyn Trait` type that has a different number of projection
+                    // bounds, which may lead to type mismatches.
+                    if !tcx.generics_require_sized_self(key.0) {
+                        missing_assoc_types.insert(key);
+                    }
                     None
                 }
             })
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 91dde13be55..4937eb73a8b 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -59,7 +59,6 @@ This API is completely unstable and subject to change.
 #![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
-#![cfg_attr(bootstrap, feature(let_chains))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
@@ -223,10 +222,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
             }
             _ => (),
         }
-    });
-
-    tcx.par_hir_body_owners(|item_def_id| {
-        let def_kind = tcx.def_kind(item_def_id);
         // Skip `AnonConst`s because we feed their `type_of`.
         if !matches!(def_kind, DefKind::AnonConst) {
             tcx.ensure_ok().typeck(item_def_id);