about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-04 17:42:07 +0000
committerbors <bors@rust-lang.org>2024-04-04 17:42:07 +0000
commita4b11c8e6057bd47f8d241baafd5ae1e813d62fd (patch)
treea433219587f683bd79f2939bf4de52549d829ee4
parent0fd571286ef6df8a6cce06d432013239a8c0665f (diff)
parent4e8d2f0040f108e3f07854b231a5987005217763 (diff)
downloadrust-a4b11c8e6057bd47f8d241baafd5ae1e813d62fd.tar.gz
rust-a4b11c8e6057bd47f8d241baafd5ae1e813d62fd.zip
Auto merge of #121394 - oli-obk:define_opaque_types, r=compiler-errors
some smaller DefiningOpaqueTypes::No -> Yes switches

r? `@compiler-errors`

These are some easy cases, so let's get them out of the way first.
I added tests exercising the specialization code paths that I believe weren't tested so far.

follow-up to https://github.com/rust-lang/rust/pull/117348
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs26
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs7
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/opaque_type.rs18
-rw-r--r--tests/ui/const-generics/generic_const_exprs/opaque_type.stderr22
-rw-r--r--tests/ui/const-generics/opaque_types.rs13
-rw-r--r--tests/ui/const-generics/opaque_types.stderr125
-rw-r--r--tests/ui/const-generics/opaque_types2.rs17
-rw-r--r--tests/ui/const-generics/opaque_types2.stderr15
-rw-r--r--tests/ui/impl-trait/nested_impl_trait.rs4
-rw-r--r--tests/ui/impl-trait/nested_impl_trait.stderr8
-rw-r--r--tests/ui/methods/opaque_param_in_ufc.rs30
-rw-r--r--tests/ui/methods/opaque_param_in_ufc.stderr36
-rw-r--r--tests/ui/self/arbitrary-self-opaque.rs12
-rw-r--r--tests/ui/self/arbitrary-self-opaque.stderr20
-rw-r--r--tests/ui/specialization/min_specialization/impl-on-opaque.rs31
-rw-r--r--tests/ui/specialization/min_specialization/impl-on-opaque2.rs28
-rw-r--r--tests/ui/specialization/min_specialization/impl-on-opaque2.stderr12
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr17
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr14
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs29
31 files changed, 522 insertions, 49 deletions
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 0e75a47683d..aa94632b2b0 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -918,7 +918,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let param = callee_args.const_at(host_effect_index);
         let cause = self.misc(span);
-        match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
+        // We know the type of `effect` to be `bool`, there will be no opaque type inference.
+        match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::Yes, effect, param) {
             Ok(infer::InferOk { obligations, value: () }) => {
                 self.register_predicates(obligations);
             }
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 564de4ab9e7..75a68f16cf1 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -400,7 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // what our ideal rcvr ty would look like.
                     let _ = self
                         .at(&ObligationCause::dummy(), self.param_env)
-                        .eq(DefineOpaqueTypes::No, method.sig.inputs()[idx + 1], arg_ty)
+                        .eq(DefineOpaqueTypes::Yes, method.sig.inputs()[idx + 1], arg_ty)
                         .ok()?;
                     self.select_obligations_where_possible(|errs| {
                         // Yeet the errors, we're already reporting errors.
@@ -479,7 +479,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .and_then(|method| {
                         let _ = self
                             .at(&ObligationCause::dummy(), self.param_env)
-                            .eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty)
+                            .eq(DefineOpaqueTypes::Yes, ideal_rcvr_ty, expected_ty)
                             .ok()?;
                         Some(method)
                     });
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index d3e6eb124f7..d8f62f7a2b6 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -44,10 +44,7 @@ use rustc_infer::infer::InferOk;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
-use rustc_middle::ty::error::{
-    ExpectedFound,
-    TypeError::{FieldMisMatch, Sorts},
-};
+use rustc_middle::ty::error::{ExpectedFound, TypeError::Sorts};
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt};
 use rustc_session::errors::ExprParenthesesNeeded;
@@ -1811,7 +1808,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 let target_ty = self.field_ty(base_expr.span, f, args);
                                 let cause = self.misc(base_expr.span);
                                 match self.at(&cause, self.param_env).sup(
-                                    DefineOpaqueTypes::No,
+                                    // We're already using inference variables for any params, and don't allow converting
+                                    // between different structs, so there is no way this ever actually defines an opaque type.
+                                    // Thus choosing `Yes` is fine.
+                                    DefineOpaqueTypes::Yes,
                                     target_ty,
                                     fru_ty,
                                 ) {
@@ -1819,16 +1819,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                         self.register_predicates(obligations)
                                     }
                                     Err(_) => {
-                                        // This should never happen, since we're just subtyping the
-                                        // remaining_fields, but it's fine to emit this, I guess.
-                                        self.err_ctxt()
-                                            .report_mismatched_types(
-                                                &cause,
-                                                target_ty,
-                                                fru_ty,
-                                                FieldMisMatch(variant.name, ident.name),
-                                            )
-                                            .emit();
+                                        span_bug!(
+                                            cause.span(),
+                                            "subtyping remaining fields of type changing FRU failed: {target_ty} != {fru_ty}: {}::{}",
+                                            variant.name,
+                                            ident.name,
+                                        );
                                     }
                                 }
                             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index f1feffcc82c..64b816553df 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -687,7 +687,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Using probe here, since we don't want this subtyping to affect inference.
             let subtyping_error = self.probe(|_| {
                 self.at(&self.misc(arg_span), self.param_env)
-                    .sup(DefineOpaqueTypes::No, formal_input_ty, coerced_ty)
+                    .sup(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty)
                     .err()
             });
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 3e89327d20f..6e5ed0a31cb 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -843,7 +843,9 @@ impl<'tcx> InferCtxt<'tcx> {
     {
         let origin = &ObligationCause::dummy();
         self.probe(|_| {
-            self.at(origin, param_env).sub(DefineOpaqueTypes::No, expected, actual).is_ok()
+            // We're only answering whether there could be a subtyping relation, and with
+            // opaque types, "there could be one", via registering a hidden type.
+            self.at(origin, param_env).sub(DefineOpaqueTypes::Yes, expected, actual).is_ok()
         })
     }
 
@@ -852,7 +854,9 @@ impl<'tcx> InferCtxt<'tcx> {
         T: at::ToTrace<'tcx>,
     {
         let origin = &ObligationCause::dummy();
-        self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::No, a, b).is_ok())
+        // We're only answering whether the types could be the same, and with
+        // opaque types, "they can be the same", via registering a hidden type.
+        self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::Yes, a, b).is_ok())
     }
 
     #[instrument(skip(self), level = "debug")]
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index a0fe6eca0fc..5d9b588b55b 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -720,7 +720,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> Result<(), NoSolution> {
         self.infcx
             .at(&ObligationCause::dummy(), param_env)
-            .eq(DefineOpaqueTypes::No, lhs, rhs)
+            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+            .eq(DefineOpaqueTypes::Yes, lhs, rhs)
             .map(|InferOk { value: (), obligations }| {
                 self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
@@ -759,7 +760,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> Result<(), NoSolution> {
         self.infcx
             .at(&ObligationCause::dummy(), param_env)
-            .sub(DefineOpaqueTypes::No, sub, sup)
+            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+            .sub(DefineOpaqueTypes::Yes, sub, sup)
             .map(|InferOk { value: (), obligations }| {
                 self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
@@ -779,7 +781,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> Result<(), NoSolution> {
         self.infcx
             .at(&ObligationCause::dummy(), param_env)
-            .relate(DefineOpaqueTypes::No, lhs, variance, rhs)
+            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+            .relate(DefineOpaqueTypes::Yes, lhs, variance, rhs)
             .map(|InferOk { value: (), obligations }| {
                 self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
@@ -803,7 +806,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
         self.infcx
             .at(&ObligationCause::dummy(), param_env)
-            .eq(DefineOpaqueTypes::No, lhs, rhs)
+            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+            .eq(DefineOpaqueTypes::Yes, lhs, rhs)
             .map(|InferOk { value: (), obligations }| {
                 obligations.into_iter().map(|o| o.into()).collect()
             })
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index e0c7804b6db..6644d3c77af 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -182,7 +182,8 @@ fn rematch_impl<'tcx>(
 
     let mut nested = infcx
         .at(&ObligationCause::dummy(), goal.param_env)
-        .eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref)
+        // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+        .eq(DefineOpaqueTypes::Yes, goal.predicate.trait_ref, impl_trait_ref)
         .map_err(|_| SelectionError::Unimplemented)?
         .into_obligations();
 
@@ -257,7 +258,8 @@ fn rematch_unsize<'tcx>(
             nested.extend(
                 infcx
                     .at(&ObligationCause::dummy(), goal.param_env)
-                    .eq(DefineOpaqueTypes::No, a_elem_ty, b_elem_ty)
+                    // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+                    .eq(DefineOpaqueTypes::Yes, a_elem_ty, b_elem_ty)
                     .expect("expected rematch to succeed")
                     .into_obligations(),
             );
@@ -300,7 +302,8 @@ fn rematch_unsize<'tcx>(
             nested.extend(
                 infcx
                     .at(&ObligationCause::dummy(), goal.param_env)
-                    .eq(DefineOpaqueTypes::No, unsized_a_ty, b_ty)
+                    // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+                    .eq(DefineOpaqueTypes::Yes, unsized_a_ty, b_ty)
                     .expect("expected rematch to succeed")
                     .into_obligations(),
             );
@@ -329,7 +332,8 @@ fn rematch_unsize<'tcx>(
             nested.extend(
                 infcx
                     .at(&ObligationCause::dummy(), goal.param_env)
-                    .eq(DefineOpaqueTypes::No, unsized_a_ty, b_ty)
+                    // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+                    .eq(DefineOpaqueTypes::Yes, unsized_a_ty, b_ty)
                     .expect("expected rematch to succeed")
                     .into_obligations(),
             );
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 90e337a53b6..8625ad378f7 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -477,7 +477,8 @@ fn plug_infer_with_placeholders<'tcx>(
             if ty.is_ty_var() {
                 let Ok(InferOk { value: (), obligations }) =
                     self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
-                        DefineOpaqueTypes::No,
+                        // Comparing against a type variable never registers hidden types anyway
+                        DefineOpaqueTypes::Yes,
                         ty,
                         Ty::new_placeholder(
                             self.infcx.tcx,
@@ -504,7 +505,9 @@ fn plug_infer_with_placeholders<'tcx>(
             if ct.is_ct_infer() {
                 let Ok(InferOk { value: (), obligations }) =
                     self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
-                        DefineOpaqueTypes::No,
+                        // The types of the constants are the same, so there is no hidden type
+                        // registration happening anyway.
+                        DefineOpaqueTypes::Yes,
                         ct,
                         ty::Const::new_placeholder(
                             self.infcx.tcx,
@@ -532,7 +535,8 @@ fn plug_infer_with_placeholders<'tcx>(
                 if r.is_var() {
                     let Ok(InferOk { value: (), obligations }) =
                         self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
-                            DefineOpaqueTypes::No,
+                            // Lifetimes don't contain opaque types (or any types for that matter).
+                            DefineOpaqueTypes::Yes,
                             r,
                             ty::Region::new_placeholder(
                                 self.infcx.tcx,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index fe2691e9d4d..af90372b97c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3842,7 +3842,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             self.probe(|_| {
                                 match self
                                     .at(&ObligationCause::misc(expr.span, body_id), param_env)
-                                    .eq(DefineOpaqueTypes::No, expected, actual)
+                                    // Doesn't actually matter if we define opaque types here, this is just used for
+                                    // diagnostics, and the result is never kept around.
+                                    .eq(DefineOpaqueTypes::Yes, expected, actual)
                                 {
                                     Ok(_) => (), // We ignore nested obligations here for now.
                                     Err(err) => type_diffs.push(err),
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index b5be9a2bcb3..88ac9d4dbe5 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -429,7 +429,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 // as the cause of an overflow.
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
                     match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
-                        DefineOpaqueTypes::No,
+                        // Only really excercised by generic_const_exprs
+                        DefineOpaqueTypes::Yes,
                         ct.ty(),
                         ty,
                     ) {
@@ -571,7 +572,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                                 if let Ok(new_obligations) = infcx
                                     .at(&obligation.cause, obligation.param_env)
                                     .trace(c1, c2)
-                                    .eq(DefineOpaqueTypes::No, a.args, b.args)
+                                    // Can define opaque types as this is only reachable with
+                                    // `generic_const_exprs`
+                                    .eq(DefineOpaqueTypes::Yes, a.args, b.args)
                                 {
                                     return ProcessResult::Changed(mk_pending(
                                         new_obligations.into_obligations(),
@@ -582,7 +585,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                             (_, _) => {
                                 if let Ok(new_obligations) = infcx
                                     .at(&obligation.cause, obligation.param_env)
-                                    .eq(DefineOpaqueTypes::No, c1, c2)
+                                    // Can define opaque types as this is only reachable with
+                                    // `generic_const_exprs`
+                                    .eq(DefineOpaqueTypes::Yes, c1, c2)
                                 {
                                     return ProcessResult::Changed(mk_pending(
                                         new_obligations.into_obligations(),
@@ -623,7 +628,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     match (evaluate(c1), evaluate(c2)) {
                         (Ok(c1), Ok(c2)) => {
                             match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
-                                DefineOpaqueTypes::No,
+                                // Can define opaque types as this is only reachable with
+                                // `generic_const_exprs`
+                                DefineOpaqueTypes::Yes,
                                 c1,
                                 c2,
                             ) {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 926044bd6a8..8fb8d21ac90 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -906,7 +906,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                     .infcx
                                     .at(&obligation.cause, obligation.param_env)
                                     .trace(c1, c2)
-                                    .eq(DefineOpaqueTypes::No, a.args, b.args)
+                                    // Can define opaque types as this is only reachable with
+                                    // `generic_const_exprs`
+                                    .eq(DefineOpaqueTypes::Yes, a.args, b.args)
                                 {
                                     return self.evaluate_predicates_recursively(
                                         previous_stack,
@@ -919,7 +921,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 if let Ok(InferOk { obligations, value: () }) = self
                                     .infcx
                                     .at(&obligation.cause, obligation.param_env)
-                                    .eq(DefineOpaqueTypes::No, c1, c2)
+                                    // Can define opaque types as this is only reachable with
+                                    // `generic_const_exprs`
+                                    .eq(DefineOpaqueTypes::Yes, c1, c2)
                                 {
                                     return self.evaluate_predicates_recursively(
                                         previous_stack,
@@ -949,7 +953,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     match (evaluate(c1), evaluate(c2)) {
                         (Ok(c1), Ok(c2)) => {
                             match self.infcx.at(&obligation.cause, obligation.param_env).eq(
-                                DefineOpaqueTypes::No,
+                                // Can define opaque types as this is only reachable with
+                                // `generic_const_exprs`
+                                DefineOpaqueTypes::Yes,
                                 c1,
                                 c2,
                             ) {
@@ -982,7 +988,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
                     match self.infcx.at(&obligation.cause, obligation.param_env).eq(
-                        DefineOpaqueTypes::No,
+                        // Only really excercised by generic_const_exprs
+                        DefineOpaqueTypes::Yes,
                         ct.ty(),
                         ty,
                     ) {
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 43c750ebbb5..ab8d7d31e43 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -247,7 +247,12 @@ fn fulfill_implication<'tcx>(
     // do the impls unify? If not, no specialization.
     let Ok(InferOk { obligations: more_obligations, .. }) = infcx
         .at(&ObligationCause::dummy(), param_env)
-        .eq(DefineOpaqueTypes::No, source_trait, target_trait)
+        // Ok to use `Yes`, as all the generic params are already replaced by inference variables,
+        // which will match the opaque type no matter if it is defining or not.
+        // Any concrete type that would match the opaque would already be handled by coherence rules,
+        // and thus either be ok to match here and already have errored, or it won't match, in which
+        // case there is no issue anyway.
+        .eq(DefineOpaqueTypes::Yes, source_trait, target_trait)
     else {
         debug!("fulfill_implication: {:?} does not unify with {:?}", source_trait, target_trait);
         return Err(());
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 47cfe651e31..72d4cc7c465 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -47,7 +47,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                 // Require the type the impl is implemented on to match
                 // our type, and ignore the impl if there was a mismatch.
                 let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(
-                    DefineOpaqueTypes::No,
+                    DefineOpaqueTypes::Yes,
                     impl_trait_ref.self_ty(),
                     impl_ty,
                 ) else {
diff --git a/tests/ui/const-generics/generic_const_exprs/opaque_type.rs b/tests/ui/const-generics/generic_const_exprs/opaque_type.rs
new file mode 100644
index 00000000000..56b8acbf88c
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/opaque_type.rs
@@ -0,0 +1,18 @@
+#![feature(generic_const_exprs, type_alias_impl_trait)]
+#![allow(incomplete_features)]
+
+type Foo = impl Sized;
+
+fn with_bound<const N: usize>() -> Foo
+where
+    [u8; (N / 2) as usize]: Sized,
+{
+    let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize];
+    //~^ ERROR mismatched types
+    //~| ERROR non-primitive cast: `usize` as `Foo`
+    todo!()
+}
+
+fn main() {
+    with_bound::<4>();
+}
diff --git a/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr b/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr
new file mode 100644
index 00000000000..e9fb8c0f403
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque_type.rs:10:17
+   |
+LL | type Foo = impl Sized;
+   |            ---------- the found opaque type
+...
+LL |     let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize];
+   |                 ^^^^^^^^^^^^^^ expected `usize`, found opaque type
+   |
+   = note:     expected type `usize`
+           found opaque type `Foo`
+
+error[E0605]: non-primitive cast: `usize` as `Foo`
+  --> $DIR/opaque_type.rs:10:17
+   |
+LL |     let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize];
+   |                 ^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0605.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/opaque_types.rs b/tests/ui/const-generics/opaque_types.rs
new file mode 100644
index 00000000000..ccf70f4fb37
--- /dev/null
+++ b/tests/ui/const-generics/opaque_types.rs
@@ -0,0 +1,13 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl Sized;
+//~^ ERROR: cycle
+//~| ERROR: cycle
+
+fn foo<const C: Foo>() {}
+//~^ ERROR: `Foo` is forbidden as the type of a const generic parameter
+
+fn main() {
+    foo::<42>();
+    //~^ ERROR: mismatched types
+}
diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr
new file mode 100644
index 00000000000..f03bca69a8b
--- /dev/null
+++ b/tests/ui/const-generics/opaque_types.stderr
@@ -0,0 +1,125 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL | type Foo = impl Sized;
+   |            ---------- the expected opaque type
+...
+LL |     foo::<42>();
+   |           ^^ expected opaque type, found integer
+   |
+   = note: expected opaque type `Foo`
+                     found type `{integer}`
+
+error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
+  --> $DIR/opaque_types.rs:3:12
+   |
+LL | type Foo = impl Sized;
+   |            ^^^^^^^^^^
+   |
+note: ...which requires computing type of opaque `Foo::{opaque#0}`...
+  --> $DIR/opaque_types.rs:3:12
+   |
+LL | type Foo = impl Sized;
+   |            ^^^^^^^^^^
+note: ...which requires type-checking `main`...
+  --> $DIR/opaque_types.rs:10:1
+   |
+LL | fn main() {
+   | ^^^^^^^^^
+note: ...which requires evaluating type-level constant...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires const-evaluating + checking `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires caching mir of `main::{constant#0}` for CTFE...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires elaborating drops for `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+   = note: ...which requires normalizing `Foo`...
+   = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking that `Foo::{opaque#0}` is well-formed
+  --> $DIR/opaque_types.rs:3:12
+   |
+LL | type Foo = impl Sized;
+   |            ^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error: `Foo` is forbidden as the type of a const generic parameter
+  --> $DIR/opaque_types.rs:7:17
+   |
+LL | fn foo<const C: Foo>() {}
+   |                 ^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+
+error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}`
+  --> $DIR/opaque_types.rs:3:12
+   |
+LL | type Foo = impl Sized;
+   |            ^^^^^^^^^^
+   |
+note: ...which requires type-checking `main`...
+  --> $DIR/opaque_types.rs:10:1
+   |
+LL | fn main() {
+   | ^^^^^^^^^
+note: ...which requires evaluating type-level constant...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires const-evaluating + checking `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires caching mir of `main::{constant#0}` for CTFE...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires elaborating drops for `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires borrow-checking `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires promoting constants in MIR for `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires const checking `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+   = note: ...which requires computing whether `Foo` is freeze...
+   = note: ...which requires evaluating trait selection obligation `Foo: core::marker::Freeze`...
+   = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle
+note: cycle used when computing type of `Foo::{opaque#0}`
+  --> $DIR/opaque_types.rs:3:12
+   |
+LL | type Foo = impl Sized;
+   |            ^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0391.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/opaque_types2.rs b/tests/ui/const-generics/opaque_types2.rs
new file mode 100644
index 00000000000..fd57438bb61
--- /dev/null
+++ b/tests/ui/const-generics/opaque_types2.rs
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl Sized;
+
+fn foo<const C: u32>() {}
+
+const C: Foo = 42;
+
+fn bar()
+where
+    Foo:,
+{
+    foo::<C>();
+    //~^ ERROR: mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/opaque_types2.stderr b/tests/ui/const-generics/opaque_types2.stderr
new file mode 100644
index 00000000000..2fb1669b7bf
--- /dev/null
+++ b/tests/ui/const-generics/opaque_types2.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque_types2.rs:13:11
+   |
+LL | type Foo = impl Sized;
+   |            ---------- the found opaque type
+...
+LL |     foo::<C>();
+   |           ^ expected `u32`, found opaque type
+   |
+   = note:     expected type `u32`
+           found opaque type `Foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/impl-trait/nested_impl_trait.rs b/tests/ui/impl-trait/nested_impl_trait.rs
index 760102794c3..502b2af2bc6 100644
--- a/tests/ui/impl-trait/nested_impl_trait.rs
+++ b/tests/ui/impl-trait/nested_impl_trait.rs
@@ -5,7 +5,7 @@ fn fine(x: impl Into<u32>) -> impl Into<u32> { x }
 
 fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
 //~^ ERROR nested `impl Trait` is not allowed
-//~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
+//~| ERROR the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
 
 fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
 //~^ ERROR nested `impl Trait` is not allowed
@@ -18,7 +18,7 @@ struct X;
 impl X {
     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
     //~^ ERROR nested `impl Trait` is not allowed
-    //~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
+    //~| ERROR the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
 }
 
 fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> {
diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr
index 83d1347aff4..1f9a2a5e9d6 100644
--- a/tests/ui/impl-trait/nested_impl_trait.stderr
+++ b/tests/ui/impl-trait/nested_impl_trait.stderr
@@ -42,20 +42,20 @@ LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
+error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
   --> $DIR/nested_impl_trait.rs:6:46
    |
 LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-   |                                              ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>`
+   |                                              ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Into<u32>`, which is required by `impl Into<u32>: Into<impl Debug>`
    |
    = help: the trait `Into<U>` is implemented for `T`
    = note: required for `impl Into<u32>` to implement `Into<impl Debug>`
 
-error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
+error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
   --> $DIR/nested_impl_trait.rs:19:34
    |
 LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-   |                                  ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>`
+   |                                  ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Into<u32>`, which is required by `impl Into<u32>: Into<impl Debug>`
    |
    = help: the trait `Into<U>` is implemented for `T`
    = note: required for `impl Into<u32>` to implement `Into<impl Debug>`
diff --git a/tests/ui/methods/opaque_param_in_ufc.rs b/tests/ui/methods/opaque_param_in_ufc.rs
new file mode 100644
index 00000000000..a4b27a0131f
--- /dev/null
+++ b/tests/ui/methods/opaque_param_in_ufc.rs
@@ -0,0 +1,30 @@
+#![feature(type_alias_impl_trait)]
+struct Foo<T>(T);
+
+impl Foo<u32> {
+    fn method() {}
+    fn method2(self) {}
+}
+
+type Bar = impl Sized;
+
+fn bar() -> Bar {
+    42_u32
+}
+
+impl Foo<Bar> {
+    fn foo() -> Bar {
+        Self::method();
+        //~^ ERROR: no function or associated item named `method` found for struct `Foo<Bar>`
+        Foo::<Bar>::method();
+        //~^ ERROR: no function or associated item named `method` found for struct `Foo<Bar>`
+        let x = Foo(bar());
+        Foo::method2(x);
+        let x = Self(bar());
+        Self::method2(x);
+        //~^ ERROR: no function or associated item named `method2` found for struct `Foo<Bar>`
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/methods/opaque_param_in_ufc.stderr b/tests/ui/methods/opaque_param_in_ufc.stderr
new file mode 100644
index 00000000000..7e5bbbac8a9
--- /dev/null
+++ b/tests/ui/methods/opaque_param_in_ufc.stderr
@@ -0,0 +1,36 @@
+error[E0599]: no function or associated item named `method` found for struct `Foo<Bar>` in the current scope
+  --> $DIR/opaque_param_in_ufc.rs:17:15
+   |
+LL | struct Foo<T>(T);
+   | ------------- function or associated item `method` not found for this struct
+...
+LL |         Self::method();
+   |               ^^^^^^ function or associated item not found in `Foo<Bar>`
+   |
+   = note: the function or associated item was found for
+           - `Foo<u32>`
+
+error[E0599]: no function or associated item named `method` found for struct `Foo<Bar>` in the current scope
+  --> $DIR/opaque_param_in_ufc.rs:19:21
+   |
+LL | struct Foo<T>(T);
+   | ------------- function or associated item `method` not found for this struct
+...
+LL |         Foo::<Bar>::method();
+   |                     ^^^^^^ function or associated item not found in `Foo<Bar>`
+   |
+   = note: the function or associated item was found for
+           - `Foo<u32>`
+
+error[E0599]: no function or associated item named `method2` found for struct `Foo<Bar>` in the current scope
+  --> $DIR/opaque_param_in_ufc.rs:24:15
+   |
+LL | struct Foo<T>(T);
+   | ------------- function or associated item `method2` not found for this struct
+...
+LL |         Self::method2(x);
+   |               ^^^^^^^ function or associated item not found in `Foo<Bar>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/self/arbitrary-self-opaque.rs b/tests/ui/self/arbitrary-self-opaque.rs
new file mode 100644
index 00000000000..99357dde3e1
--- /dev/null
+++ b/tests/ui/self/arbitrary-self-opaque.rs
@@ -0,0 +1,12 @@
+#![feature(type_alias_impl_trait)]
+struct Foo;
+
+type Bar = impl Sized;
+//~^ ERROR unconstrained opaque type
+
+impl Foo {
+    fn foo(self: Bar) {}
+    //~^ ERROR: invalid `self` parameter type: Bar
+}
+
+fn main() {}
diff --git a/tests/ui/self/arbitrary-self-opaque.stderr b/tests/ui/self/arbitrary-self-opaque.stderr
new file mode 100644
index 00000000000..6b5db8d8493
--- /dev/null
+++ b/tests/ui/self/arbitrary-self-opaque.stderr
@@ -0,0 +1,20 @@
+error: unconstrained opaque type
+  --> $DIR/arbitrary-self-opaque.rs:4:12
+   |
+LL | type Bar = impl Sized;
+   |            ^^^^^^^^^^
+   |
+   = note: `Bar` must be used in combination with a concrete type within the same module
+
+error[E0307]: invalid `self` parameter type: Bar
+  --> $DIR/arbitrary-self-opaque.rs:8:18
+   |
+LL |     fn foo(self: Bar) {}
+   |                  ^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0307`.
diff --git a/tests/ui/specialization/min_specialization/impl-on-opaque.rs b/tests/ui/specialization/min_specialization/impl-on-opaque.rs
new file mode 100644
index 00000000000..7531dcaccf2
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/impl-on-opaque.rs
@@ -0,0 +1,31 @@
+// Test that specializing on opaque types is allowed
+
+//@ check-pass
+
+#![feature(min_specialization, type_alias_impl_trait)]
+
+trait SpecTrait<U> {
+    fn f();
+}
+
+impl<U> SpecTrait<U> for () {
+    default fn f() {}
+}
+
+type Opaque = impl Tuple;
+
+trait Tuple {}
+
+impl Tuple for () {}
+
+impl SpecTrait<Opaque> for () {
+    fn f() {}
+}
+
+impl SpecTrait<u32> for () {
+    fn f() {}
+}
+
+fn foo() -> Opaque {}
+
+fn main() {}
diff --git a/tests/ui/specialization/min_specialization/impl-on-opaque2.rs b/tests/ui/specialization/min_specialization/impl-on-opaque2.rs
new file mode 100644
index 00000000000..0cd8be84ed3
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/impl-on-opaque2.rs
@@ -0,0 +1,28 @@
+// Test that specializing on opaque types is allowed
+
+#![feature(min_specialization, type_alias_impl_trait)]
+
+trait SpecTrait<U, V> {
+    fn f();
+}
+
+impl<U> SpecTrait<U, ()> for () {
+    default fn f() {}
+}
+
+type Opaque = impl Tuple;
+
+trait Tuple {}
+
+impl Tuple for () {}
+
+// FIXME: this passes if we use `<(), ()>` here instead of `<(), Opaque>`,
+// even though there can't be more overlap from the opaque version
+impl SpecTrait<(), Opaque> for () {
+    //~^ ERROR: conflicting implementations
+    fn f() {}
+}
+
+fn foo() -> Opaque {}
+
+fn main() {}
diff --git a/tests/ui/specialization/min_specialization/impl-on-opaque2.stderr b/tests/ui/specialization/min_specialization/impl-on-opaque2.stderr
new file mode 100644
index 00000000000..3c0bc8f8f83
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/impl-on-opaque2.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `SpecTrait<(), ()>` for type `()`
+  --> $DIR/impl-on-opaque2.rs:21:1
+   |
+LL | impl<U> SpecTrait<U, ()> for () {
+   | ------------------------------- first implementation here
+...
+LL | impl SpecTrait<(), Opaque> for () {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr
new file mode 100644
index 00000000000..c54a1c42bad
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/illegal-upcast-from-impl-opaque.rs:26:5
+   |
+LL | type Foo = impl Sized;
+   |            ---------- the found opaque type
+LL |
+LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
+   |                                         ----------------------- expected `&dyn Super<Assoc = i32>` because of return type
+LL |     x
+   |     ^ expected trait `Super`, found trait `Sub`
+   |
+   = note: expected reference `&dyn Super<Assoc = i32>`
+              found reference `&dyn Sub<Assoc = Foo>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr
new file mode 100644
index 00000000000..3c2bc0b9190
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr
@@ -0,0 +1,14 @@
+error: internal compiler error: error performing operation: query type op
+  --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1
+   |
+LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: 
+  --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1
+   |
+LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+query stack during panic:
+end of query stack
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs
new file mode 100644
index 00000000000..f344474054a
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs
@@ -0,0 +1,29 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@[next] failure-status: 101
+//@[next] known-bug: unknown
+//@[next] normalize-stderr-test "note: .*\n\n" -> ""
+//@[next] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
+//@[next] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
+//@[next] normalize-stderr-test "delayed at .*" -> ""
+//@[next] rustc-env:RUST_BACKTRACE=0
+
+#![feature(trait_upcasting, type_alias_impl_trait)]
+
+trait Super {
+    type Assoc;
+}
+
+trait Sub: Super {}
+
+impl<T: ?Sized> Super for T {
+    type Assoc = i32;
+}
+
+type Foo = impl Sized;
+
+fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
+    x //[current]~ mismatched types
+}
+
+fn main() {}