about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-01-03 05:01:14 +0000
committerMichael Goulet <michael@errs.io>2025-01-03 05:01:14 +0000
commit2d602ea7931ca6988a34567d9255a10c09d0e17e (patch)
tree162e73434158f2a8dfdded085ce36f262f419b0e
parentab3924b298eb78bf4c96cf7e6b5824f8debbf2b9 (diff)
downloadrust-2d602ea7931ca6988a34567d9255a10c09d0e17e.tar.gz
rust-2d602ea7931ca6988a34567d9255a10c09d0e17e.zip
Do not project when there are unconstrained impl params
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs123
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs63
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs14
-rw-r--r--tests/crashes/123141.rs23
-rw-r--r--tests/crashes/125874.rs22
-rw-r--r--tests/crashes/126942.rs11
-rw-r--r--tests/crashes/127804.rs12
-rw-r--r--tests/crashes/130967.rs13
-rw-r--r--tests/ui/generic-associated-types/bugs/issue-87735.stderr68
-rw-r--r--tests/ui/impl-trait/in-trait/refine-resolution-errors.rs1
-rw-r--r--tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr11
-rw-r--r--tests/ui/impl-trait/issues/issue-87340.rs2
-rw-r--r--tests/ui/impl-trait/issues/issue-87340.stderr17
-rw-r--r--tests/ui/impl-unused-tps.stderr12
-rw-r--r--tests/ui/traits/unconstrained-projection-normalization-2.rs17
-rw-r--r--tests/ui/traits/unconstrained-projection-normalization-2.stderr9
-rw-r--r--tests/ui/traits/unconstrained-projection-normalization.rs16
-rw-r--r--tests/ui/traits/unconstrained-projection-normalization.stderr9
-rw-r--r--tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs1
-rw-r--r--tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr15
-rw-r--r--tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr17
-rw-r--r--tests/ui/type-alias-impl-trait/issue-74244.rs1
-rw-r--r--tests/ui/type-alias-impl-trait/issue-74244.stderr11
26 files changed, 214 insertions, 283 deletions
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index d9c70c3cee6..bb122009593 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -57,22 +57,24 @@ pub(crate) fn check_impl_wf(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
 ) -> Result<(), ErrorGuaranteed> {
-    let min_specialization = tcx.features().min_specialization();
-    let mut res = Ok(());
     debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. });
-    res = res.and(enforce_impl_params_are_constrained(tcx, impl_def_id));
-    if min_specialization {
+
+    // Check that the args are constrained. We queryfied the check for ty/const params
+    // since unconstrained type/const params cause ICEs in projection, so we want to
+    // detect those specifically and project those to `TyKind::Error`.
+    let mut res = tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
+    res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id));
+
+    if tcx.features().min_specialization() {
         res = res.and(check_min_specialization(tcx, impl_def_id));
     }
-
     res
 }
 
-fn enforce_impl_params_are_constrained(
+pub(crate) fn enforce_impl_lifetime_params_are_constrained(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
 ) -> Result<(), ErrorGuaranteed> {
-    // Every lifetime used in an associated type must be constrained.
     let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
     if impl_self_ty.references_error() {
         // Don't complain about unconstrained type params when self ty isn't known due to errors.
@@ -88,6 +90,7 @@ fn enforce_impl_params_are_constrained(
         // Compilation must continue in order for other important diagnostics to keep showing up.
         return Ok(());
     }
+
     let impl_generics = tcx.generics_of(impl_def_id);
     let impl_predicates = tcx.predicates_of(impl_def_id);
     let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
@@ -123,21 +126,98 @@ fn enforce_impl_params_are_constrained(
 
     let mut res = Ok(());
     for param in &impl_generics.own_params {
+        match param.kind {
+            ty::GenericParamDefKind::Lifetime => {
+                let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
+                if lifetimes_in_associated_types.contains(&param_lt) // (*)
+                    && !input_parameters.contains(&param_lt)
+                {
+                    let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
+                        span: tcx.def_span(param.def_id),
+                        param_name: param.name,
+                        param_def_kind: tcx.def_descr(param.def_id),
+                        const_param_note: false,
+                        const_param_note2: false,
+                    });
+                    diag.code(E0207);
+                    res = Err(diag.emit());
+                }
+                // (*) This is a horrible concession to reality. I think it'd be
+                // better to just ban unconstrained lifetimes outright, but in
+                // practice people do non-hygienic macros like:
+                //
+                // ```
+                // macro_rules! __impl_slice_eq1 {
+                //   ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
+                //     impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
+                //        ....
+                //     }
+                //   }
+                // }
+                // ```
+                //
+                // In a concession to backwards compatibility, we continue to
+                // permit those, so long as the lifetimes aren't used in
+                // associated types. I believe this is sound, because lifetimes
+                // used elsewhere are not projected back out.
+            }
+            ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
+                // Enforced in `enforce_impl_non_lifetime_params_are_constrained`.
+            }
+        }
+    }
+    res
+}
+
+pub(crate) fn enforce_impl_non_lifetime_params_are_constrained(
+    tcx: TyCtxt<'_>,
+    impl_def_id: LocalDefId,
+) -> Result<(), ErrorGuaranteed> {
+    let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
+    if impl_self_ty.references_error() {
+        // Don't complain about unconstrained type params when self ty isn't known due to errors.
+        // (#36836)
+        tcx.dcx().span_delayed_bug(
+            tcx.def_span(impl_def_id),
+            format!(
+                "potentially unconstrained type parameters weren't evaluated: {impl_self_ty:?}",
+            ),
+        );
+        // This is super fishy, but our current `rustc_hir_analysis::check_crate` pipeline depends on
+        // `type_of` having been called much earlier, and thus this value being read from cache.
+        // Compilation must continue in order for other important diagnostics to keep showing up.
+        return Ok(());
+    }
+    let impl_generics = tcx.generics_of(impl_def_id);
+    let impl_predicates = tcx.predicates_of(impl_def_id);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
+
+    impl_trait_ref.error_reported()?;
+
+    let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
+    cgp::identify_constrained_generic_params(
+        tcx,
+        impl_predicates,
+        impl_trait_ref,
+        &mut input_parameters,
+    );
+
+    let mut res = Ok(());
+    for param in &impl_generics.own_params {
         let err = match param.kind {
             // Disallow ANY unconstrained type parameters.
             ty::GenericParamDefKind::Type { .. } => {
                 let param_ty = ty::ParamTy::for_def(param);
                 !input_parameters.contains(&cgp::Parameter::from(param_ty))
             }
-            ty::GenericParamDefKind::Lifetime => {
-                let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
-                lifetimes_in_associated_types.contains(&param_lt) && // (*)
-                    !input_parameters.contains(&param_lt)
-            }
             ty::GenericParamDefKind::Const { .. } => {
                 let param_ct = ty::ParamConst::for_def(param);
                 !input_parameters.contains(&cgp::Parameter::from(param_ct))
             }
+            ty::GenericParamDefKind::Lifetime => {
+                // Enforced in `enforce_impl_type_params_are_constrained`.
+                false
+            }
         };
         if err {
             let const_param_note = matches!(param.kind, ty::GenericParamDefKind::Const { .. });
@@ -153,23 +233,4 @@ fn enforce_impl_params_are_constrained(
         }
     }
     res
-
-    // (*) This is a horrible concession to reality. I think it'd be
-    // better to just ban unconstrained lifetimes outright, but in
-    // practice people do non-hygienic macros like:
-    //
-    // ```
-    // macro_rules! __impl_slice_eq1 {
-    //     ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
-    //         impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
-    //            ....
-    //         }
-    //     }
-    // }
-    // ```
-    //
-    // In a concession to backwards compatibility, we continue to
-    // permit those, so long as the lifetimes aren't used in
-    // associated types. I believe this is sound, because lifetimes
-    // used elsewhere are not projected back out.
 }
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 87fd4de26a5..a42a168234f 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -128,6 +128,8 @@ pub fn provide(providers: &mut Providers) {
     hir_wf_check::provide(providers);
     *providers = Providers {
         inherit_sig_for_delegation_item: delegation::inherit_sig_for_delegation_item,
+        enforce_impl_non_lifetime_params_are_constrained:
+            impl_wf_check::enforce_impl_non_lifetime_params_are_constrained,
         ..*providers
     };
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 7e7b602c560..8b8467472f5 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1719,6 +1719,11 @@ rustc_queries! {
         ensure_forwards_result_if_red
     }
 
+    query enforce_impl_non_lifetime_params_are_constrained(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
+        desc { |tcx| "checking that `{}`'s generics are constrained by the impl header", tcx.def_path_str(key) }
+        ensure_forwards_result_if_red
+    }
+
     // The `DefId`s of all non-generic functions and statics in the given crate
     // that can be reached from outside the crate.
     //
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 54407d17dcf..69b7d5cff1e 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -950,39 +950,45 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 //
                 // NOTE: This should be kept in sync with the similar code in
                 // `rustc_ty_utils::instance::resolve_associated_item()`.
-                let node_item = specialization_graph::assoc_def(
+                match specialization_graph::assoc_def(
                     selcx.tcx(),
                     impl_data.impl_def_id,
                     obligation.predicate.def_id,
-                )
-                .map_err(|ErrorGuaranteed { .. }| ())?;
-
-                if node_item.is_final() {
-                    // Non-specializable items are always projectable.
-                    true
-                } else {
-                    // Only reveal a specializable default if we're past type-checking
-                    // and the obligation is monomorphic, otherwise passes such as
-                    // transmute checking and polymorphic MIR optimizations could
-                    // get a result which isn't correct for all monomorphizations.
-                    match selcx.infcx.typing_mode() {
-                        TypingMode::Coherence
-                        | TypingMode::Analysis { .. }
-                        | TypingMode::PostBorrowckAnalysis { .. } => {
-                            debug!(
-                                assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
-                                ?obligation.predicate,
-                                "assemble_candidates_from_impls: not eligible due to default",
-                            );
-                            false
-                        }
-                        TypingMode::PostAnalysis => {
-                            // NOTE(eddyb) inference variables can resolve to parameters, so
-                            // assume `poly_trait_ref` isn't monomorphic, if it contains any.
-                            let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(trait_ref);
-                            !poly_trait_ref.still_further_specializable()
+                ) {
+                    Ok(node_item) => {
+                        if node_item.is_final() {
+                            // Non-specializable items are always projectable.
+                            true
+                        } else {
+                            // Only reveal a specializable default if we're past type-checking
+                            // and the obligation is monomorphic, otherwise passes such as
+                            // transmute checking and polymorphic MIR optimizations could
+                            // get a result which isn't correct for all monomorphizations.
+                            match selcx.infcx.typing_mode() {
+                                TypingMode::Coherence
+                                | TypingMode::Analysis { .. }
+                                | TypingMode::PostBorrowckAnalysis { .. } => {
+                                    debug!(
+                                        assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
+                                        ?obligation.predicate,
+                                        "not eligible due to default",
+                                    );
+                                    false
+                                }
+                                TypingMode::PostAnalysis => {
+                                    // NOTE(eddyb) inference variables can resolve to parameters, so
+                                    // assume `poly_trait_ref` isn't monomorphic, if it contains any.
+                                    let poly_trait_ref =
+                                        selcx.infcx.resolve_vars_if_possible(trait_ref);
+                                    !poly_trait_ref.still_further_specializable()
+                                }
+                            }
                         }
                     }
+                    // Always project `ErrorGuaranteed`, since this will just help
+                    // us propagate `TyKind::Error` around which suppresses ICEs
+                    // and spurious, unrelated inference errors.
+                    Err(ErrorGuaranteed { .. }) => true,
                 }
             }
             ImplSource::Builtin(BuiltinImplSource::Misc, _) => {
@@ -2014,7 +2020,6 @@ fn confirm_impl_candidate<'cx, 'tcx>(
         Ok(assoc_ty) => assoc_ty,
         Err(guar) => return Progress::error(tcx, guar),
     };
-
     if !assoc_ty.item.defaultness(tcx).has_value() {
         // This means that the impl is missing a definition for the
         // associated type. This error will be reported by the type
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 13620f4b8d9..c351cf5aaac 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -376,6 +376,12 @@ pub(crate) fn assoc_def(
     // If there is no such item in that impl, this function will fail with a
     // cycle error if the specialization graph is currently being built.
     if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_def_id) {
+        // Ensure that the impl is constrained, otherwise projection may give us
+        // bad unconstrained infer vars.
+        if let Some(impl_def_id) = impl_def_id.as_local() {
+            tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
+        }
+
         let item = tcx.associated_item(impl_item_id);
         let impl_node = Node::Impl(impl_def_id);
         return Ok(LeafDef {
@@ -391,6 +397,14 @@ pub(crate) fn assoc_def(
 
     let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
     if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_def_id) {
+        // Ensure that the impl is constrained, otherwise projection may give us
+        // bad unconstrained infer vars.
+        if assoc_item.item.container == ty::AssocItemContainer::Impl
+            && let Some(impl_def_id) = assoc_item.item.container_id(tcx).as_local()
+        {
+            tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
+        }
+
         Ok(assoc_item)
     } else {
         // This is saying that neither the trait nor
diff --git a/tests/crashes/123141.rs b/tests/crashes/123141.rs
deleted file mode 100644
index 07181387e04..00000000000
--- a/tests/crashes/123141.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-//@ known-bug: #123141
-
-trait Trait {
-    fn next(self) -> Self::Item;
-    type Item;
-}
-
-struct Foo<T: ?Sized>(T);
-
-impl<T: ?Sized, U> Trait for Foo<U> {
-    type Item = Foo<T>;
-    fn next(self) -> Self::Item {
-        loop {}
-    }
-}
-
-fn opaque() -> impl Trait {
-    Foo::<_>(10_u32)
-}
-
-fn main() {
-    opaque().next();
-}
diff --git a/tests/crashes/125874.rs b/tests/crashes/125874.rs
deleted file mode 100644
index 6a2713cd7c8..00000000000
--- a/tests/crashes/125874.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-//@ known-bug: rust-lang/rust#125874
-pub trait A {}
-
-pub trait Mirror {
-    type Assoc: ?Sized;
-}
-impl<T: ?Sized> Mirror for dyn A {
-    type Assoc = T;
-}
-
-struct Bar {
-    foo: <dyn A + 'static as Mirror>::Assoc,
-}
-
-pub fn main() {
-    let strct = Bar { foo: 3 };
-
-    match strct {
-        Bar { foo: 1, .. } => {}
-        _ => (),
-    };
-}
diff --git a/tests/crashes/126942.rs b/tests/crashes/126942.rs
deleted file mode 100644
index e4adc8fab28..00000000000
--- a/tests/crashes/126942.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ known-bug: rust-lang/rust#126942
-struct Thing;
-
-pub trait Every {
-    type Assoc;
-}
-impl<T: ?Sized> Every for Thing {
-    type Assoc = T;
-}
-
-static I: <Thing as Every>::Assoc = 3;
diff --git a/tests/crashes/127804.rs b/tests/crashes/127804.rs
deleted file mode 100644
index e583a7c1fc6..00000000000
--- a/tests/crashes/127804.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ known-bug: #127804
-
-struct Thing;
-
-pub trait Every {
-    type Assoc;
-}
-impl<T: ?Sized> Every for Thing {
-    type Assoc = T;
-}
-
-fn foo(_: <Thing as Every>::Assoc) {}
diff --git a/tests/crashes/130967.rs b/tests/crashes/130967.rs
deleted file mode 100644
index 8a3aae72c20..00000000000
--- a/tests/crashes/130967.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ known-bug: #130967
-
-trait Producer {
-    type Produced;
-    fn make_one() -> Self::Produced;
-}
-
-impl<E: ?Sized> Producer for () {
-    type Produced = Option<E>;
-    fn make_one() -> Self::Produced {
-        loop {}
-    }
-}
diff --git a/tests/ui/generic-associated-types/bugs/issue-87735.stderr b/tests/ui/generic-associated-types/bugs/issue-87735.stderr
index d8005065238..1b955431363 100644
--- a/tests/ui/generic-associated-types/bugs/issue-87735.stderr
+++ b/tests/ui/generic-associated-types/bugs/issue-87735.stderr
@@ -22,73 +22,7 @@ help: consider adding an explicit lifetime bound
 LL |   type Output<'a> = FooRef<'a, U> where Self: 'a, U: 'a;
    |                                                 +++++++
 
-error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/issue-87735.rs:31:15
-   |
-LL | impl<'b, T, U> AsRef2 for Foo<T>
-   |      -- the parameter type `T` must be valid for the lifetime `'b` as defined here...
-...
-LL |     T: AsRef2<Output<'b> = &'b [U]>,
-   |               ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
-   |
-note: ...that is required by this bound
-  --> $DIR/issue-87735.rs:7:31
-   |
-LL |   type Output<'a> where Self: 'a;
-   |                               ^^
-help: consider adding an explicit lifetime bound
-   |
-LL |     T: AsRef2<Output<'b> = &'b [U]> + 'b,
-   |                                     ++++
-
-error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/issue-87735.rs:36:31
-   |
-LL | impl<'b, T, U> AsRef2 for Foo<T>
-   |      -- the parameter type `T` must be valid for the lifetime `'b` as defined here...
-...
-LL |   fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
-   |                               ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
-   |
-note: ...that is required by this bound
-  --> $DIR/issue-87735.rs:7:31
-   |
-LL |   type Output<'a> where Self: 'a;
-   |                               ^^
-help: consider adding an explicit lifetime bound
-   |
-LL |     T: AsRef2<Output<'b> = &'b [U]> + 'b,
-   |                                     ++++
-
-error: lifetime may not live long enough
-  --> $DIR/issue-87735.rs:37:5
-   |
-LL | impl<'b, T, U> AsRef2 for Foo<T>
-   |      -- lifetime `'b` defined here
-...
-LL |   fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
-   |              -- lifetime `'a` defined here
-LL |     FooRef(self.0.as_ref2())
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
-   |
-   = help: consider adding the following bound: `'b: 'a`
-
-error: lifetime may not live long enough
-  --> $DIR/issue-87735.rs:37:12
-   |
-LL | impl<'b, T, U> AsRef2 for Foo<T>
-   |      -- lifetime `'b` defined here
-...
-LL |   fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
-   |              -- lifetime `'a` defined here
-LL |     FooRef(self.0.as_ref2())
-   |            ^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
-   |
-   = help: consider adding the following bound: `'a: 'b`
-
-help: `'b` and `'a` must be the same: replace one with the other
-
-error: aborting due to 6 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0207, E0309.
 For more information about an error, try `rustc --explain E0207`.
diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs b/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs
index a9936c7bc3f..894f592d9e2 100644
--- a/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs
+++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs
@@ -13,7 +13,6 @@ impl<T: ?Sized> Mirror for () {
 
 pub trait First {
     async fn first() -> <() as Mirror>::Assoc;
-    //~^ ERROR type annotations needed
 }
 
 impl First for () {
diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr
index 0f5573dda04..10ebad2a7d5 100644
--- a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr
+++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr
@@ -4,13 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self
 LL | impl<T: ?Sized> Mirror for () {
    |      ^ unconstrained type parameter
 
-error[E0282]: type annotations needed
-  --> $DIR/refine-resolution-errors.rs:15:5
-   |
-LL |     async fn first() -> <() as Mirror>::Assoc;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0207, E0282.
-For more information about an error, try `rustc --explain E0207`.
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/impl-trait/issues/issue-87340.rs b/tests/ui/impl-trait/issues/issue-87340.rs
index b1baaaa6ba5..705a4addcb7 100644
--- a/tests/ui/impl-trait/issues/issue-87340.rs
+++ b/tests/ui/impl-trait/issues/issue-87340.rs
@@ -9,8 +9,6 @@ impl<T> X for () {
     //~^ ERROR `T` is not constrained by the impl trait, self type, or predicates
     type I = impl Sized;
     fn f() -> Self::I {}
-    //~^ ERROR type annotations needed
-    //~| ERROR type annotations needed
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/issues/issue-87340.stderr b/tests/ui/impl-trait/issues/issue-87340.stderr
index 1be4087be42..8513cb2881e 100644
--- a/tests/ui/impl-trait/issues/issue-87340.stderr
+++ b/tests/ui/impl-trait/issues/issue-87340.stderr
@@ -4,19 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self
 LL | impl<T> X for () {
    |      ^ unconstrained type parameter
 
-error[E0282]: type annotations needed
-  --> $DIR/issue-87340.rs:11:23
-   |
-LL |     fn f() -> Self::I {}
-   |                       ^^ cannot infer type for type parameter `T`
-
-error[E0282]: type annotations needed
-  --> $DIR/issue-87340.rs:11:15
-   |
-LL |     fn f() -> Self::I {}
-   |               ^^^^^^^ cannot infer type for type parameter `T`
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0207, E0282.
-For more information about an error, try `rustc --explain E0207`.
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/impl-unused-tps.stderr b/tests/ui/impl-unused-tps.stderr
index da4589dee82..09c3fce641c 100644
--- a/tests/ui/impl-unused-tps.stderr
+++ b/tests/ui/impl-unused-tps.stderr
@@ -7,6 +7,12 @@ LL | impl<T> Foo<T> for [isize; 0] {
 LL | impl<T, U> Foo<T> for U {
    | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]`
 
+error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/impl-unused-tps.rs:32:9
+   |
+LL | impl<T, U> Bar for T {
+   |         ^ unconstrained type parameter
+
 error[E0119]: conflicting implementations of trait `Bar`
   --> $DIR/impl-unused-tps.rs:40:1
    |
@@ -47,12 +53,6 @@ LL | impl<T, U> Foo<T> for [isize; 1] {
    |         ^ unconstrained type parameter
 
 error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/impl-unused-tps.rs:32:9
-   |
-LL | impl<T, U> Bar for T {
-   |         ^ unconstrained type parameter
-
-error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
   --> $DIR/impl-unused-tps.rs:40:9
    |
 LL | impl<T, U> Bar for T
diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.rs b/tests/ui/traits/unconstrained-projection-normalization-2.rs
new file mode 100644
index 00000000000..085e9e4a61a
--- /dev/null
+++ b/tests/ui/traits/unconstrained-projection-normalization-2.rs
@@ -0,0 +1,17 @@
+// Make sure we don't ICE in `normalize_erasing_regions` when normalizing
+// an associated type in an impl with unconstrained non-lifetime params.
+// (This time in a function signature)
+
+struct Thing;
+
+pub trait Every {
+    type Assoc;
+}
+impl<T: ?Sized> Every for Thing {
+//~^ ERROR the type parameter `T` is not constrained
+    type Assoc = T;
+}
+
+fn foo(_: <Thing as Every>::Assoc) {}
+
+fn main() {}
diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.stderr b/tests/ui/traits/unconstrained-projection-normalization-2.stderr
new file mode 100644
index 00000000000..6d3d4492b07
--- /dev/null
+++ b/tests/ui/traits/unconstrained-projection-normalization-2.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained-projection-normalization-2.rs:10:6
+   |
+LL | impl<T: ?Sized> Every for Thing {
+   |      ^ unconstrained type parameter
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/traits/unconstrained-projection-normalization.rs b/tests/ui/traits/unconstrained-projection-normalization.rs
new file mode 100644
index 00000000000..e4d25a5ba6c
--- /dev/null
+++ b/tests/ui/traits/unconstrained-projection-normalization.rs
@@ -0,0 +1,16 @@
+// Make sure we don't ICE in `normalize_erasing_regions` when normalizing
+// an associated type in an impl with unconstrained non-lifetime params.
+
+struct Thing;
+
+pub trait Every {
+    type Assoc;
+}
+impl<T: ?Sized> Every for Thing {
+//~^ ERROR the type parameter `T` is not constrained
+    type Assoc = T;
+}
+
+static I: <Thing as Every>::Assoc = 3;
+
+fn main() {}
diff --git a/tests/ui/traits/unconstrained-projection-normalization.stderr b/tests/ui/traits/unconstrained-projection-normalization.stderr
new file mode 100644
index 00000000000..4e4421a73e5
--- /dev/null
+++ b/tests/ui/traits/unconstrained-projection-normalization.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained-projection-normalization.rs:9:6
+   |
+LL | impl<T: ?Sized> Every for Thing {
+   |      ^ unconstrained type parameter
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs
index 0ee188d825f..2bcb8f06f4f 100644
--- a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs
+++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs
@@ -42,7 +42,6 @@ impl<T: MyFrom<Phantom2<DummyT<U>>>, U> MyIndex<DummyT<T>> for Scope<U> {
     //~^ ERROR the type parameter `T` is not constrained by the impl
     type O = T;
     fn my_index(self) -> Self::O {
-        //~^ ERROR item does not constrain
         MyFrom::my_from(self.0).ok().unwrap()
     }
 }
diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr
index eace96317dc..0ab4c34381a 100644
--- a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr
+++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr
@@ -17,19 +17,6 @@ note: this opaque type is in the signature
 LL | type DummyT<T> = impl F;
    |                  ^^^^^^
 
-error: item does not constrain `DummyT::{opaque#0}`, but has it in its signature
-  --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:44:8
-   |
-LL |     fn my_index(self) -> Self::O {
-   |        ^^^^^^^^
-   |
-   = note: consider moving the opaque type's declaration and defining uses into a separate module
-note: this opaque type is in the signature
-  --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:20:18
-   |
-LL | type DummyT<T> = impl F;
-   |                  ^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs b/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs
index fcac83500ec..1824ff5e2fb 100644
--- a/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs
+++ b/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs
@@ -12,8 +12,6 @@ impl<T> X for () {
     //~^ ERROR the type parameter `T` is not constrained
     type I = impl Sized;
     fn f() -> Self::I {}
-    //~^ ERROR type annotations needed
-    //~| ERROR type annotations needed
 }
 
 fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr b/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr
index bb0e11d314c..137a4db81b5 100644
--- a/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr
+++ b/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr
@@ -4,19 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self
 LL | impl<T> X for () {
    |      ^ unconstrained type parameter
 
-error[E0282]: type annotations needed
-  --> $DIR/impl-with-unconstrained-param.rs:14:23
-   |
-LL |     fn f() -> Self::I {}
-   |                       ^^ cannot infer type for type parameter `T`
-
-error[E0282]: type annotations needed
-  --> $DIR/impl-with-unconstrained-param.rs:14:15
-   |
-LL |     fn f() -> Self::I {}
-   |               ^^^^^^^ cannot infer type for type parameter `T`
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0207, E0282.
-For more information about an error, try `rustc --explain E0207`.
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/type-alias-impl-trait/issue-74244.rs b/tests/ui/type-alias-impl-trait/issue-74244.rs
index ce8a38a3361..bb4104b3d25 100644
--- a/tests/ui/type-alias-impl-trait/issue-74244.rs
+++ b/tests/ui/type-alias-impl-trait/issue-74244.rs
@@ -14,7 +14,6 @@ impl<T> Allocator for DefaultAllocator {
 type A = impl Fn(<DefaultAllocator as Allocator>::Buffer);
 
 fn foo() -> A {
-    //~^ ERROR: type annotations needed
     |_| ()
 }
 
diff --git a/tests/ui/type-alias-impl-trait/issue-74244.stderr b/tests/ui/type-alias-impl-trait/issue-74244.stderr
index d2b50ffd86b..f5ca56baccc 100644
--- a/tests/ui/type-alias-impl-trait/issue-74244.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-74244.stderr
@@ -4,13 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self
 LL | impl<T> Allocator for DefaultAllocator {
    |      ^ unconstrained type parameter
 
-error[E0282]: type annotations needed
-  --> $DIR/issue-74244.rs:16:13
-   |
-LL | fn foo() -> A {
-   |             ^ cannot infer type for type parameter `T`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0207, E0282.
-For more information about an error, try `rustc --explain E0207`.
+For more information about this error, try `rustc --explain E0207`.