about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-09-07 18:12:05 +0000
committerbors <bors@rust-lang.org>2024-09-07 18:12:05 +0000
commitec867f03bcd6c39156ef13eb5f85bf4fb924ca29 (patch)
tree93b51c48db24efa58e43951970b0c3ae9c84b885
parent4ff16a97702f1764564139a8c4aaf7936e5d43e4 (diff)
parent588dce14211bdfb1305c495f01c697e29e946e10 (diff)
downloadrust-ec867f03bcd6c39156ef13eb5f85bf4fb924ca29.tar.gz
rust-ec867f03bcd6c39156ef13eb5f85bf4fb924ca29.zip
Auto merge of #126161 - Bryanskiy:delegation-generics-4, r=petrochenkov
Delegation: support generics in associated delegation items

This is a continuation of https://github.com/rust-lang/rust/pull/125929.

[design](https://github.com/Bryanskiy/posts/blob/master/delegation%20in%20generic%20contexts.md)

Generic parameters inheritance was implemented in all contexts. Generic arguments are not yet supported.

r? `@petrochenkov`
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/delegation.rs445
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs3
-rw-r--r--tests/ui/delegation/generics/impl-to-free-fn-pass.rs29
-rw-r--r--tests/ui/delegation/generics/impl-to-trait-method.rs44
-rw-r--r--tests/ui/delegation/generics/impl-to-trait-method.stderr49
-rw-r--r--tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs77
-rw-r--r--tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs23
-rw-r--r--tests/ui/delegation/generics/trait-method-to-other-pass.rs30
-rw-r--r--tests/ui/delegation/ice-issue-124347.rs4
-rw-r--r--tests/ui/delegation/ice-issue-124347.stderr14
-rw-r--r--tests/ui/delegation/not-supported.rs116
-rw-r--r--tests/ui/delegation/not-supported.stderr204
-rw-r--r--tests/ui/delegation/unsupported.rs57
-rw-r--r--tests/ui/delegation/unsupported.stderr95
16 files changed, 777 insertions, 445 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index be6c3f048dc..ba01ea3f512 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -59,6 +59,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
 
     let node = tcx.hir_node(hir_id);
+    if let Some(sig) = node.fn_sig()
+        && let Some(sig_id) = sig.decl.opt_delegation_sig_id()
+    {
+        return inherit_generics_for_delegation_item(tcx, def_id, sig_id);
+    }
+
     let parent_def_id = match node {
         Node::ImplItem(_)
         | Node::TraitItem(_)
@@ -229,16 +235,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 // inherit the generics of the item.
                 Some(parent.to_def_id())
             }
-            ItemKind::Fn(sig, _, _) => {
-                // For a delegation item inherit generics from callee.
-                if let Some(sig_id) = sig.decl.opt_delegation_sig_id()
-                    && let Some(generics) =
-                        inherit_generics_for_delegation_item(tcx, def_id, sig_id)
-                {
-                    return generics;
-                }
-                None
-            }
             _ => None,
         },
         _ => None,
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index a47aaf25e95..7243e85ce98 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -138,6 +138,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
     let node = tcx.hir_node(hir_id);
 
+    if let Some(sig) = node.fn_sig()
+        && let Some(sig_id) = sig.decl.opt_delegation_sig_id()
+    {
+        return inherit_predicates_for_delegation_item(tcx, def_id, sig_id);
+    }
+
     let mut is_trait = None;
     let mut is_default_impl_trait = None;
 
@@ -164,16 +170,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => {
                 is_trait = Some(self_bounds);
             }
-
-            ItemKind::Fn(sig, _, _) => {
-                // For a delegation item inherit predicates from callee.
-                if let Some(sig_id) = sig.decl.opt_delegation_sig_id()
-                    && let Some(predicates) =
-                        inherit_predicates_for_delegation_item(tcx, def_id, sig_id)
-                {
-                    return predicates;
-                }
-            }
             _ => {}
         }
     };
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
index 20aaa43219f..2c9f20b7840 100644
--- a/compiler/rustc_hir_analysis/src/delegation.rs
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -1,3 +1,7 @@
+//! Support inheriting generic parameters and predicates for function delegation.
+//!
+//! For more information about delegation design, see the tracking issue #118212.
+
 use std::assert_matches::debug_assert_matches;
 
 use rustc_data_structures::fx::FxHashMap;
@@ -5,7 +9,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::ErrorGuaranteed;
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_type_ir::visit::TypeVisitableExt;
 
 type RemapTable = FxHashMap<u32, u32>;
@@ -76,127 +80,381 @@ fn fn_kind<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> FnKind {
     }
 }
 
+/// Given the current context(caller and callee `FnKind`), it specifies
+/// the policy of predicates and generic parameters inheritance.
+#[derive(Clone, Copy, Debug, PartialEq)]
+enum InheritanceKind {
+    /// Copying all predicates and parameters, including those of the parent
+    /// container.
+    ///
+    /// Boolean value defines whether the `Self` parameter or `Self: Trait`
+    /// predicate are copied. It's always equal to `false` except when
+    /// delegating from a free function to a trait method.
+    ///
+    /// FIXME(fn_delegation): This often leads to type inference
+    /// errors. Support providing generic arguments or restrict use sites.
+    WithParent(bool),
+    /// The trait implementation should be compatible with the original trait.
+    /// Therefore, for trait implementations only the method's own parameters
+    /// and predicates are copied.
+    Own,
+}
+
+struct GenericsBuilder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    sig_id: DefId,
+    parent: Option<DefId>,
+    inh_kind: InheritanceKind,
+}
+
+impl<'tcx> GenericsBuilder<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, sig_id: DefId) -> GenericsBuilder<'tcx> {
+        GenericsBuilder { tcx, sig_id, parent: None, inh_kind: InheritanceKind::WithParent(false) }
+    }
+
+    fn with_parent(mut self, parent: DefId) -> Self {
+        self.parent = Some(parent);
+        self
+    }
+
+    fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self {
+        self.inh_kind = inh_kind;
+        self
+    }
+
+    fn build(self) -> ty::Generics {
+        let mut own_params = vec![];
+
+        let sig_generics = self.tcx.generics_of(self.sig_id);
+        if let InheritanceKind::WithParent(has_self) = self.inh_kind
+            && let Some(parent_def_id) = sig_generics.parent
+        {
+            let sig_parent_generics = self.tcx.generics_of(parent_def_id);
+            own_params.append(&mut sig_parent_generics.own_params.clone());
+            if !has_self {
+                own_params.remove(0);
+            }
+        }
+        own_params.append(&mut sig_generics.own_params.clone());
+
+        // Lifetime parameters must be declared before type and const parameters.
+        // Therefore, When delegating from a free function to a associated function,
+        // generic parameters need to be reordered:
+        //
+        // trait Trait<'a, A> {
+        //     fn foo<'b, B>(...) {...}
+        // }
+        //
+        // reuse Trait::foo;
+        // desugaring:
+        // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
+        //     Trait::foo(...)
+        // }
+        own_params.sort_by_key(|key| key.kind.is_ty_or_const());
+
+        let param_def_id_to_index =
+            own_params.iter().map(|param| (param.def_id, param.index)).collect();
+
+        let (parent_count, has_self) = if let Some(def_id) = self.parent {
+            let parent_generics = self.tcx.generics_of(def_id);
+            let parent_kind = self.tcx.def_kind(def_id);
+            (parent_generics.count(), parent_kind == DefKind::Trait)
+        } else {
+            (0, false)
+        };
+
+        for (idx, param) in own_params.iter_mut().enumerate() {
+            param.index = (idx + parent_count) as u32;
+            // FIXME(fn_delegation): Default parameters are not inherited, because they are
+            // not permitted in functions. Therefore, there are 2 options here:
+            //
+            // - We can create non-default generic parameters.
+            // - We can substitute default parameters into the signature.
+            //
+            // At the moment, first option has been selected as the most general.
+            if let ty::GenericParamDefKind::Type { has_default, .. }
+            | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind
+            {
+                *has_default = false;
+            }
+        }
+
+        ty::Generics {
+            parent: self.parent,
+            parent_count,
+            own_params,
+            param_def_id_to_index,
+            has_self,
+            has_late_bound_regions: sig_generics.has_late_bound_regions,
+            host_effect_index: sig_generics.host_effect_index,
+        }
+    }
+}
+
+struct PredicatesBuilder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    sig_id: DefId,
+    parent: Option<DefId>,
+    inh_kind: InheritanceKind,
+    args: ty::GenericArgsRef<'tcx>,
+}
+
+impl<'tcx> PredicatesBuilder<'tcx> {
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        args: ty::GenericArgsRef<'tcx>,
+        sig_id: DefId,
+    ) -> PredicatesBuilder<'tcx> {
+        PredicatesBuilder {
+            tcx,
+            sig_id,
+            parent: None,
+            inh_kind: InheritanceKind::WithParent(false),
+            args,
+        }
+    }
+
+    fn with_parent(mut self, parent: DefId) -> Self {
+        self.parent = Some(parent);
+        self
+    }
+
+    fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self {
+        self.inh_kind = inh_kind;
+        self
+    }
+
+    fn build(self) -> ty::GenericPredicates<'tcx> {
+        struct PredicatesCollector<'tcx> {
+            tcx: TyCtxt<'tcx>,
+            preds: Vec<(ty::Clause<'tcx>, Span)>,
+            args: ty::GenericArgsRef<'tcx>,
+        }
+
+        impl<'tcx> PredicatesCollector<'tcx> {
+            fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> {
+                PredicatesCollector { tcx, preds: vec![], args }
+            }
+
+            fn with_own_preds(
+                mut self,
+                f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>,
+                def_id: DefId,
+            ) -> Self {
+                let preds = f(def_id).instantiate_own(self.tcx, self.args);
+                self.preds.extend(preds);
+                self
+            }
+
+            fn with_preds(
+                mut self,
+                f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy,
+                def_id: DefId,
+            ) -> Self {
+                let preds = f(def_id);
+                if let Some(parent_def_id) = preds.parent {
+                    self = self.with_own_preds(f, parent_def_id);
+                }
+                self.with_own_preds(f, def_id)
+            }
+        }
+        let collector = PredicatesCollector::new(self.tcx, self.args);
+
+        // `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate.
+        // Note: `predicates_of` query can also add inferred outlives predicates, but that
+        // is not the case here as `sig_id` is either a trait or a function.
+        let preds = match self.inh_kind {
+            InheritanceKind::WithParent(false) => {
+                collector.with_preds(|def_id| self.tcx.explicit_predicates_of(def_id), self.sig_id)
+            }
+            InheritanceKind::WithParent(true) => {
+                collector.with_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id)
+            }
+            InheritanceKind::Own => {
+                collector.with_own_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id)
+            }
+        }
+        .preds;
+
+        ty::GenericPredicates {
+            parent: self.parent,
+            predicates: self.tcx.arena.alloc_from_iter(preds),
+            // FIXME(fn_delegation): Support effects.
+            effects_min_tys: ty::List::empty(),
+        }
+    }
+}
+
+struct GenericArgsBuilder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    remap_table: RemapTable,
+    sig_id: DefId,
+    def_id: LocalDefId,
+}
+
+impl<'tcx> GenericArgsBuilder<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, sig_id: DefId, def_id: LocalDefId) -> GenericArgsBuilder<'tcx> {
+        GenericArgsBuilder { tcx, remap_table: FxHashMap::default(), sig_id, def_id }
+    }
+
+    fn build_from_args(mut self, args: ty::GenericArgsRef<'tcx>) -> ty::GenericArgsRef<'tcx> {
+        let caller_generics = self.tcx.generics_of(self.def_id);
+        let callee_generics = self.tcx.generics_of(self.sig_id);
+
+        for caller_param in &caller_generics.own_params {
+            let callee_index =
+                callee_generics.param_def_id_to_index(self.tcx, caller_param.def_id).unwrap();
+            self.remap_table.insert(callee_index, caller_param.index);
+        }
+
+        let mut folder = ParamIndexRemapper { tcx: self.tcx, remap_table: self.remap_table };
+        args.fold_with(&mut folder)
+    }
+}
+
 fn create_generic_args<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
     sig_id: DefId,
 ) -> ty::GenericArgsRef<'tcx> {
-    let caller_generics = tcx.generics_of(def_id);
-    let callee_generics = tcx.generics_of(sig_id);
+    let builder = GenericArgsBuilder::new(tcx, sig_id, def_id);
 
     let caller_kind = fn_kind(tcx, def_id.into());
     let callee_kind = fn_kind(tcx, sig_id);
-    // FIXME(fn_delegation): Support generics on associated delegation items.
-    // Error will be reported in `check_constraints`.
     match (caller_kind, callee_kind) {
-        (FnKind::Free, _) => {
-            // Lifetime parameters must be declared before type and const parameters.
-            // Therefore, When delegating from a free function to a associated function,
-            // generic parameters need to be reordered:
-            //
-            // trait Trait<'a, A> {
-            //     fn foo<'b, B>(...) {...}
-            // }
-            //
-            // reuse Trait::foo;
-            // desugaring:
-            // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
-            //     Trait::foo(...)
-            // }
-            let mut remap_table = RemapTable::default();
-            for caller_param in &caller_generics.own_params {
-                let callee_index =
-                    callee_generics.param_def_id_to_index(tcx, caller_param.def_id).unwrap();
-                remap_table.insert(callee_index, caller_param.index);
-            }
-            let mut folder = ParamIndexRemapper { tcx, remap_table };
-            ty::GenericArgs::identity_for_item(tcx, sig_id).fold_with(&mut folder)
+        (FnKind::Free, FnKind::Free)
+        | (FnKind::Free, FnKind::AssocTrait)
+        | (FnKind::AssocInherentImpl, FnKind::Free)
+        | (FnKind::AssocTrait, FnKind::Free)
+        | (FnKind::AssocTrait, FnKind::AssocTrait) => {
+            let args = ty::GenericArgs::identity_for_item(tcx, sig_id);
+            builder.build_from_args(args)
         }
-        // FIXME(fn_delegation): Only `Self` param supported here.
-        (FnKind::AssocTraitImpl, FnKind::AssocTrait)
-        | (FnKind::AssocInherentImpl, FnKind::AssocTrait) => {
+
+        (FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
+            let callee_generics = tcx.generics_of(sig_id);
+            let parent = tcx.parent(def_id.into());
+            let parent_args =
+                tcx.impl_trait_header(parent).unwrap().trait_ref.instantiate_identity().args;
+
+            let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id);
+            let method_args = tcx.mk_args_from_iter(trait_args.iter().skip(callee_generics.parent_count));
+            let method_args = builder.build_from_args(method_args);
+
+            tcx.mk_args_from_iter(parent_args.iter().chain(method_args))
+        }
+
+        (FnKind::AssocInherentImpl, FnKind::AssocTrait) => {
             let parent = tcx.parent(def_id.into());
             let self_ty = tcx.type_of(parent).instantiate_identity();
             let generic_self_ty = ty::GenericArg::from(self_ty);
-            tcx.mk_args_from_iter(std::iter::once(generic_self_ty))
+
+            let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id);
+            let trait_args = builder.build_from_args(trait_args);
+
+            let args = std::iter::once(generic_self_ty).chain(trait_args.iter().skip(1));
+            tcx.mk_args_from_iter(args)
         }
-        _ => ty::GenericArgs::identity_for_item(tcx, sig_id),
+
+        // For trait impl's `sig_id` is always equal to the corresponding trait method.
+        (FnKind::AssocTraitImpl, _)
+        | (_, FnKind::AssocTraitImpl)
+        // Delegation to inherent methods is not yet supported.
+        | (_, FnKind::AssocInherentImpl) => unreachable!(),
     }
 }
 
+// FIXME(fn_delegation): Move generics inheritance to the AST->HIR lowering.
+// For now, generic parameters are not propagated to the generated call,
+// which leads to inference errors:
+//
+// fn foo<T>(x: i32) {}
+//
+// reuse foo as bar;
+// desugaring:
+// fn bar<T>() {
+//   foo::<_>() // ERROR: type annotations needed
+// }
 pub(crate) fn inherit_generics_for_delegation_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
     sig_id: DefId,
-) -> Option<ty::Generics> {
-    // FIXME(fn_delegation): Support generics on associated delegation items.
-    // Error will be reported in `check_constraints`.
-    if fn_kind(tcx, def_id.into()) != FnKind::Free {
-        return None;
-    }
+) -> ty::Generics {
+    let builder = GenericsBuilder::new(tcx, sig_id);
 
-    let mut own_params = vec![];
-
-    let callee_generics = tcx.generics_of(sig_id);
-    if let Some(parent_sig_id) = callee_generics.parent {
-        let parent_sig_generics = tcx.generics_of(parent_sig_id);
-        own_params.append(&mut parent_sig_generics.own_params.clone());
-    }
-    own_params.append(&mut callee_generics.own_params.clone());
+    let caller_kind = fn_kind(tcx, def_id.into());
+    let callee_kind = fn_kind(tcx, sig_id);
+    match (caller_kind, callee_kind) {
+        (FnKind::Free, FnKind::Free)
+        | (FnKind::Free, FnKind::AssocTrait) => builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build(),
+
+        (FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
+            builder
+            .with_parent(tcx.parent(def_id.into()))
+            .with_inheritance_kind(InheritanceKind::Own)
+            .build()
+        }
 
-    // Lifetimes go first.
-    own_params.sort_by_key(|key| key.kind.is_ty_or_const());
+        (FnKind::AssocInherentImpl, FnKind::AssocTrait)
+        | (FnKind::AssocTrait, FnKind::AssocTrait) => {
+            builder
+            .with_parent(tcx.parent(def_id.into()))
+            .build()
+        }
 
-    for (idx, param) in own_params.iter_mut().enumerate() {
-        param.index = idx as u32;
-        // Default parameters are not inherited: they are not allowed
-        // in fn's.
-        if let ty::GenericParamDefKind::Type { has_default, .. }
-        | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind
-        {
-            *has_default = false;
+        (FnKind::AssocInherentImpl, FnKind::Free)
+        | (FnKind::AssocTrait, FnKind::Free) => {
+            builder
+            .with_parent(tcx.parent(def_id.into()))
+            .build()
         }
-    }
 
-    let param_def_id_to_index =
-        own_params.iter().map(|param| (param.def_id, param.index)).collect();
-
-    Some(ty::Generics {
-        parent: None,
-        parent_count: 0,
-        own_params,
-        param_def_id_to_index,
-        has_self: false,
-        has_late_bound_regions: callee_generics.has_late_bound_regions,
-        host_effect_index: callee_generics.host_effect_index,
-    })
+        // For trait impl's `sig_id` is always equal to the corresponding trait method.
+        (FnKind::AssocTraitImpl, _)
+        | (_, FnKind::AssocTraitImpl)
+        // Delegation to inherent methods is not yet supported.
+        | (_, FnKind::AssocInherentImpl) => unreachable!(),
+    }
 }
 
 pub(crate) fn inherit_predicates_for_delegation_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
     sig_id: DefId,
-) -> Option<ty::GenericPredicates<'tcx>> {
-    // FIXME(fn_delegation): Support generics on associated delegation items.
-    // Error will be reported in `check_constraints`.
-    if fn_kind(tcx, def_id.into()) != FnKind::Free {
-        return None;
-    }
-
-    let callee_predicates = tcx.predicates_of(sig_id);
+) -> ty::GenericPredicates<'tcx> {
     let args = create_generic_args(tcx, def_id, sig_id);
+    let builder = PredicatesBuilder::new(tcx, args, sig_id);
 
-    let mut preds = vec![];
-    if let Some(parent_id) = callee_predicates.parent {
-        preds.extend(tcx.predicates_of(parent_id).instantiate_own(tcx, args));
-    }
-    preds.extend(callee_predicates.instantiate_own(tcx, args));
+    let caller_kind = fn_kind(tcx, def_id.into());
+    let callee_kind = fn_kind(tcx, sig_id);
+    match (caller_kind, callee_kind) {
+        (FnKind::Free, FnKind::Free)
+        | (FnKind::Free, FnKind::AssocTrait) => {
+            builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build()
+        }
+
+        (FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
+            builder
+            .with_parent(tcx.parent(def_id.into()))
+            .with_inheritance_kind(InheritanceKind::Own)
+            .build()
+        }
+
+        (FnKind::AssocInherentImpl, FnKind::AssocTrait)
+        | (FnKind::AssocTrait, FnKind::AssocTrait)
+        | (FnKind::AssocInherentImpl, FnKind::Free)
+        | (FnKind::AssocTrait, FnKind::Free) => {
+            builder
+                .with_parent(tcx.parent(def_id.into()))
+                .build()
+        }
 
-    Some(ty::GenericPredicates {
-        parent: None,
-        predicates: tcx.arena.alloc_from_iter(preds),
-        effects_min_tys: ty::List::empty(),
-    })
+        // For trait impl's `sig_id` is always equal to the corresponding trait method.
+        (FnKind::AssocTraitImpl, _)
+        | (_, FnKind::AssocTraitImpl)
+        // Delegation to inherent methods is not yet supported.
+        | (_, FnKind::AssocInherentImpl) => unreachable!(),
+    }
 }
 
 fn check_constraints<'tcx>(
@@ -224,19 +482,6 @@ fn check_constraints<'tcx>(
         emit("recursive delegation is not supported yet");
     }
 
-    if fn_kind(tcx, def_id.into()) != FnKind::Free {
-        let sig_generics = tcx.generics_of(sig_id);
-        let parent = tcx.parent(def_id.into());
-        let parent_generics = tcx.generics_of(parent);
-
-        let parent_has_self = parent_generics.has_self as usize;
-        let sig_has_self = sig_generics.has_self as usize;
-
-        if sig_generics.count() > sig_has_self || parent_generics.count() > parent_has_self {
-            emit("early bound generics are not supported for associated delegation items");
-        }
-    }
-
     ret
 }
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index a93b633ce1a..cf9891f15ad 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -1296,6 +1296,9 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
             && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
             && self.tecx.tcx.trait_of_item(def_id).is_some()
             && !has_impl_trait(def_id)
+            // FIXME(fn_delegation): In delegation item argument spans are equal to last path
+            // segment. This leads to ICE's when emitting `multipart_suggestion`.
+            && tcx.hir().opt_delegation_sig_id(expr.hir_id.owner.def_id).is_none()
         {
             let successor =
                 method_args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
diff --git a/tests/ui/delegation/generics/impl-to-free-fn-pass.rs b/tests/ui/delegation/generics/impl-to-free-fn-pass.rs
new file mode 100644
index 00000000000..3b39a457467
--- /dev/null
+++ b/tests/ui/delegation/generics/impl-to-free-fn-pass.rs
@@ -0,0 +1,29 @@
+//@ run-pass
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod to_reuse {
+    pub fn foo<T, U>(_: T, y: U) -> U { y }
+}
+
+trait Trait<T> {
+    fn foo(&self, x: T) -> T { x }
+}
+struct F;
+impl<T> Trait<T> for F {}
+
+struct S<T>(F, T);
+
+impl<T, U> Trait<T> for S<U> {
+    reuse to_reuse::foo { &self.0 }
+}
+
+impl<T> S<T> {
+    reuse to_reuse::foo;
+}
+
+fn main() {
+    let s = S(F, 42);
+    assert_eq!(S::<i32>::foo(F, 1), 1);
+    assert_eq!(<S<_> as Trait<_>>::foo(&s, 1), 1);
+}
diff --git a/tests/ui/delegation/generics/impl-to-trait-method.rs b/tests/ui/delegation/generics/impl-to-trait-method.rs
new file mode 100644
index 00000000000..39e32e2ed15
--- /dev/null
+++ b/tests/ui/delegation/generics/impl-to-trait-method.rs
@@ -0,0 +1,44 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod bounds {
+    trait Trait0 {}
+
+    trait Trait1<T> {
+        fn foo<U>(&self)
+        where
+            T: Trait0,
+            U: Trait0,
+            Self: Trait0,
+            //~^ ERROR the trait bound `bounds::S: Trait0` is not satisfied
+        {
+        }
+    }
+
+    struct F;
+    impl<T> Trait1<T> for F {}
+
+    struct S(F);
+
+    impl<T> Trait1<T> for S {
+        reuse Trait1::<T>::foo { &self.0 }
+        //~^ ERROR the trait bound `bounds::F: Trait0` is not satisfied
+    }
+}
+
+mod unconstrained_parameter {
+    trait Trait<T> {
+        fn foo(&self) {}
+    }
+
+    struct F;
+    impl<T> Trait<T> for F {}
+
+    struct S(F);
+    impl S {
+        reuse Trait::foo { &self.0 }
+        //~^ ERROR type annotations needed
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/generics/impl-to-trait-method.stderr b/tests/ui/delegation/generics/impl-to-trait-method.stderr
new file mode 100644
index 00000000000..aeba30de043
--- /dev/null
+++ b/tests/ui/delegation/generics/impl-to-trait-method.stderr
@@ -0,0 +1,49 @@
+error[E0277]: the trait bound `bounds::S: Trait0` is not satisfied
+  --> $DIR/impl-to-trait-method.rs:12:19
+   |
+LL |             Self: Trait0,
+   |                   ^^^^^^ the trait `Trait0` is not implemented for `bounds::S`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/impl-to-trait-method.rs:5:5
+   |
+LL |     trait Trait0 {}
+   |     ^^^^^^^^^^^^
+   = help: see issue #48214
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+LL + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `bounds::F: Trait0` is not satisfied
+  --> $DIR/impl-to-trait-method.rs:24:34
+   |
+LL |         reuse Trait1::<T>::foo { &self.0 }
+   |                            ---   ^^^^^^^ the trait `Trait0` is not implemented for `bounds::F`
+   |                            |
+   |                            required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/impl-to-trait-method.rs:5:5
+   |
+LL |     trait Trait0 {}
+   |     ^^^^^^^^^^^^
+note: required by a bound in `Trait1::foo`
+  --> $DIR/impl-to-trait-method.rs:12:19
+   |
+LL |         fn foo<U>(&self)
+   |            --- required by a bound in this associated function
+...
+LL |             Self: Trait0,
+   |                   ^^^^^^ required by this bound in `Trait1::foo`
+
+error[E0282]: type annotations needed
+  --> $DIR/impl-to-trait-method.rs:39:22
+   |
+LL |         reuse Trait::foo { &self.0 }
+   |                      ^^^ cannot infer type for type parameter `T` declared on the trait `Trait`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0282.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs b/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs
new file mode 100644
index 00000000000..72440fe82d4
--- /dev/null
+++ b/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs
@@ -0,0 +1,77 @@
+//@ run-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+use std::iter::{Iterator, Map};
+
+pub mod same_trait {
+    use super::*;
+
+    pub struct MapOuter<I, F> {
+        pub inner: Map<I, F>
+    }
+
+    impl<B, I: Iterator, F> Iterator for MapOuter<I, F>
+    where
+        F: FnMut(I::Item) -> B,
+    {
+        type Item = <Map<I, F> as Iterator>::Item;
+
+        reuse Iterator::{next, fold} { self.inner }
+    }
+}
+use same_trait::MapOuter;
+
+mod another_trait {
+    use super::*;
+
+    trait ZipImpl<A, B> {
+        type Item;
+
+        fn next(&mut self) -> Option<Self::Item>;
+    }
+
+    pub struct Zip<A, B> {
+        pub a: A,
+        pub b: B,
+    }
+
+    impl<A: Iterator, B: Iterator> ZipImpl<A, B> for Zip<A, B> {
+        type Item = (A::Item, B::Item);
+
+        fn next(&mut self) -> Option<(A::Item, B::Item)> {
+            let x = self.a.next()?;
+            let y = self.b.next()?;
+            Some((x, y))
+        }
+    }
+
+    impl<A: Iterator, B: Iterator> Iterator for Zip<A, B> {
+        type Item = (A::Item, B::Item);
+
+        // Parameters are inherited from `Iterator::next`, not from `ZipImpl::next`.
+        // Otherwise, there would be a compilation error due to an unconstrained parameter.
+        reuse ZipImpl::next;
+    }
+}
+use another_trait::Zip;
+
+fn main() {
+    {
+        let x = vec![1, 2, 3];
+        let iter = x.iter().map(|val| val * 2);
+        let outer_iter = MapOuter { inner: iter };
+        let val = outer_iter.fold(0, |acc, x| acc + x);
+        assert_eq!(val, 12);
+    }
+
+    {
+        let x = vec![1, 2];
+        let y = vec![4, 5];
+
+        let mut zip = Zip { a: x.iter(), b: y.iter() };
+        assert_eq!(zip.next(), Some((&1, &4)));
+        assert_eq!(zip.next(), Some((&2, &5)));
+    }
+}
diff --git a/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs b/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs
new file mode 100644
index 00000000000..6f3bb178971
--- /dev/null
+++ b/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs
@@ -0,0 +1,23 @@
+//@ run-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait<T> {
+    fn foo<U>(&self, x: T, y: U) -> (T, U) {
+        (x, y)
+    }
+}
+
+impl<T> Trait<T> for () {}
+struct S<T>(T, ());
+
+impl<T> S<T> {
+    reuse Trait::foo { self.1 }
+}
+
+
+fn main() {
+    let s = S((), ());
+    assert_eq!(s.foo(1u32, 2i32), (1u32, 2i32));
+}
diff --git a/tests/ui/delegation/generics/trait-method-to-other-pass.rs b/tests/ui/delegation/generics/trait-method-to-other-pass.rs
new file mode 100644
index 00000000000..2094705a05c
--- /dev/null
+++ b/tests/ui/delegation/generics/trait-method-to-other-pass.rs
@@ -0,0 +1,30 @@
+//@ run-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod to_reuse {
+    pub fn foo<T>(x: T) -> T { x }
+}
+
+trait Trait1<T, U> {
+    fn foo(&self, _: T, x: U) -> U { x }
+}
+
+#[derive(Default)]
+struct F;
+
+impl<T, U> Trait1<T, U> for F {}
+
+trait Trait2<T> {
+    fn get_f(&self) -> &F { &F }
+    reuse Trait1::foo as bar { self.get_f() }
+    reuse to_reuse::foo as baz;
+}
+
+impl Trait2<u64> for F {}
+
+fn main() {
+    assert_eq!(F.bar(1u8, 2u16), 2u16);
+    assert_eq!(F::baz(1u8), 1u8);
+}
diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs
index 3bfae8face5..ee2bf9e33eb 100644
--- a/tests/ui/delegation/ice-issue-124347.rs
+++ b/tests/ui/delegation/ice-issue-124347.rs
@@ -1,12 +1,12 @@
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
 
+// FIXME(fn_delegation): `recursive delegation` error should be emitted here
 trait Trait {
     reuse Trait::foo { &self.0 }
-    //~^ ERROR recursive delegation is not supported yet
+    //~^ ERROR cycle detected when computing generics of `Trait::foo`
 }
 
-// FIXME(fn_delegation): `recursive delegation` error should be emitted here
 reuse foo;
 //~^ ERROR cycle detected when computing generics of `foo`
 
diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr
index 87dd75ffec8..bd0bc970b94 100644
--- a/tests/ui/delegation/ice-issue-124347.stderr
+++ b/tests/ui/delegation/ice-issue-124347.stderr
@@ -1,8 +1,16 @@
-error: recursive delegation is not supported yet
-  --> $DIR/ice-issue-124347.rs:5:18
+error[E0391]: cycle detected when computing generics of `Trait::foo`
+  --> $DIR/ice-issue-124347.rs:6:18
    |
 LL |     reuse Trait::foo { &self.0 }
-   |                  ^^^ callee defined here
+   |                  ^^^
+   |
+   = note: ...which immediately requires computing generics of `Trait::foo` again
+note: cycle used when inheriting delegation signature
+  --> $DIR/ice-issue-124347.rs:6:18
+   |
+LL |     reuse Trait::foo { &self.0 }
+   |                  ^^^
+   = 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[E0391]: cycle detected when computing generics of `foo`
   --> $DIR/ice-issue-124347.rs:10:7
diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs
deleted file mode 100644
index d5ac68ecf1b..00000000000
--- a/tests/ui/delegation/not-supported.rs
+++ /dev/null
@@ -1,116 +0,0 @@
-#![feature(const_trait_impl)]
-#![feature(c_variadic)]
-#![feature(effects)]
-#![feature(fn_delegation)]
-#![allow(incomplete_features)]
-
-mod generics {
-    trait GenericTrait<T> {
-        fn bar(&self, x: T) -> T { x }
-        fn bar1() {}
-    }
-    trait Trait {
-        fn foo(&self, x: i32) -> i32 { x }
-        fn foo1<'a>(&self, x: &'a i32) -> &'a i32 { x }
-        fn foo2<T>(&self, x: T) -> T { x }
-        fn foo3<'a: 'a>(_: &'a u32) {}
-
-        reuse GenericTrait::bar;
-        //~^ ERROR early bound generics are not supported for associated delegation items
-        reuse GenericTrait::bar1;
-        //~^ ERROR early bound generics are not supported for associated delegation items
-    }
-
-    struct F;
-    impl Trait for F {}
-    impl<T> GenericTrait<T> for F {}
-
-    struct S(F);
-
-    impl<T> GenericTrait<T> for S {
-        reuse <F as GenericTrait<T>>::bar { &self.0 }
-        //~^ ERROR early bound generics are not supported for associated delegation items
-        reuse GenericTrait::<T>::bar1;
-        //~^ ERROR early bound generics are not supported for associated delegation items
-    }
-
-    impl GenericTrait<()> for () {
-        reuse GenericTrait::bar { &F }
-        //~^ ERROR early bound generics are not supported for associated delegation items
-        reuse GenericTrait::bar1;
-        //~^ ERROR early bound generics are not supported for associated delegation items
-    }
-
-    impl Trait for &S {
-        reuse Trait::foo;
-        //~^ ERROR early bound generics are not supported for associated delegation items
-    }
-
-    impl Trait for S {
-        reuse Trait::foo1 { &self.0 }
-        reuse Trait::foo2 { &self.0 }
-        //~^ ERROR early bound generics are not supported for associated delegation items
-        //~| ERROR method `foo2` has 0 type parameters but its trait declaration has 1 type parameter
-        reuse <F as Trait>::foo3;
-        //~^ ERROR early bound generics are not supported for associated delegation items
-        //~| ERROR lifetime parameters or bounds on associated function `foo3` do not match the trait declaration
-    }
-
-    struct GenericS<T>(T);
-    impl<T> Trait for GenericS<T> {
-        reuse Trait::foo { &self.0 }
-        //~^ ERROR early bound generics are not supported for associated delegation items
-    }
-}
-
-mod opaque {
-    trait Trait {}
-    impl Trait for () {}
-
-    mod to_reuse {
-        use super::Trait;
-
-        pub fn opaque_ret() -> impl Trait { unimplemented!() }
-        //~^ warn: this function depends on never type fallback being `()`
-        //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-    }
-
-    trait ToReuse {
-        fn opaque_ret() -> impl Trait { unimplemented!() }
-        //~^ warn: this function depends on never type fallback being `()`
-        //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-    }
-
-    // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls.
-    impl ToReuse for u8 {
-        reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type
-    }
-    impl ToReuse for u16 {
-        reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type
-    }
-}
-
-mod recursive {
-    mod to_reuse1 {
-        pub mod to_reuse2 {
-            pub fn foo() {}
-        }
-
-        pub reuse to_reuse2::foo;
-    }
-
-    reuse to_reuse1::foo;
-    //~^ ERROR recursive delegation is not supported yet
-}
-
-mod effects {
-    #[const_trait]
-    trait Trait {
-        fn foo();
-    }
-
-    reuse Trait::foo;
-    //~^ ERROR delegation to a function with effect parameter is not supported yet
-}
-
-fn main() {}
diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr
deleted file mode 100644
index 14d6b374bd2..00000000000
--- a/tests/ui/delegation/not-supported.stderr
+++ /dev/null
@@ -1,204 +0,0 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: early bound generics are not supported for associated delegation items
-  --> $DIR/not-supported.rs:18:29
-   |
-LL |         fn bar(&self, x: T) -> T { x }
-   |         ------------------------ callee defined here
-...
-LL |         reuse GenericTrait::bar;
-   |                             ^^^
-
-error: early bound generics are not supported for associated delegation items
-  --> $DIR/not-supported.rs:20:29
-   |
-LL |         fn bar1() {}
-   |         --------- callee defined here
-...
-LL |         reuse GenericTrait::bar1;
-   |                             ^^^^
-
-error: early bound generics are not supported for associated delegation items
-  --> $DIR/not-supported.rs:31:39
-   |
-LL |         fn bar(&self, x: T) -> T { x }
-   |         ------------------------ callee defined here
-...
-LL |         reuse <F as GenericTrait<T>>::bar { &self.0 }
-   |                                       ^^^
-
-error: early bound generics are not supported for associated delegation items
-  --> $DIR/not-supported.rs:33:34
-   |
-LL |         fn bar1() {}
-   |         --------- callee defined here
-...
-LL |         reuse GenericTrait::<T>::bar1;
-   |                                  ^^^^
-
-error: early bound generics are not supported for associated delegation items
-  --> $DIR/not-supported.rs:38:29
-   |
-LL |         fn bar(&self, x: T) -> T { x }
-   |         ------------------------ callee defined here
-...
-LL |         reuse GenericTrait::bar { &F }
-   |                             ^^^
-
-error: early bound generics are not supported for associated delegation items
-  --> $DIR/not-supported.rs:40:29
-   |
-LL |         fn bar1() {}
-   |         --------- callee defined here
-...
-LL |         reuse GenericTrait::bar1;
-   |                             ^^^^
-
-error: early bound generics are not supported for associated delegation items
-  --> $DIR/not-supported.rs:45:22
-   |
-LL |         fn foo(&self, x: i32) -> i32 { x }
-   |         ---------------------------- callee defined here
-...
-LL |         reuse Trait::foo;
-   |                      ^^^
-
-error[E0049]: method `foo2` has 0 type parameters but its trait declaration has 1 type parameter
-  --> $DIR/not-supported.rs:51:22
-   |
-LL |         fn foo2<T>(&self, x: T) -> T { x }
-   |                 - expected 1 type parameter
-...
-LL |         reuse Trait::foo2 { &self.0 }
-   |                      ^^^^ found 0 type parameters
-
-error: early bound generics are not supported for associated delegation items
-  --> $DIR/not-supported.rs:54:29
-   |
-LL |         fn foo3<'a: 'a>(_: &'a u32) {}
-   |         --------------------------- callee defined here
-...
-LL |         reuse <F as Trait>::foo3;
-   |                             ^^^^
-
-error[E0195]: lifetime parameters or bounds on associated function `foo3` do not match the trait declaration
-  --> $DIR/not-supported.rs:54:29
-   |
-LL |         fn foo3<'a: 'a>(_: &'a u32) {}
-   |                -------- lifetimes in impl do not match this associated function in trait
-...
-LL |         reuse <F as Trait>::foo3;
-   |                             ^^^^ lifetimes do not match associated function in trait
-
-error: delegation to a function with effect parameter is not supported yet
-  --> $DIR/not-supported.rs:112:18
-   |
-LL |         fn foo();
-   |         --------- callee defined here
-...
-LL |     reuse Trait::foo;
-   |                  ^^^
-
-error: early bound generics are not supported for associated delegation items
-  --> $DIR/not-supported.rs:61:22
-   |
-LL |         fn foo(&self, x: i32) -> i32 { x }
-   |         ---------------------------- callee defined here
-...
-LL |         reuse Trait::foo { &self.0 }
-   |                      ^^^
-
-error: early bound generics are not supported for associated delegation items
-  --> $DIR/not-supported.rs:51:22
-   |
-LL |         fn foo2<T>(&self, x: T) -> T { x }
-   |         ---------------------------- callee defined here
-...
-LL |         reuse Trait::foo2 { &self.0 }
-   |                      ^^^^
-
-warning: this function depends on never type fallback being `()`
-  --> $DIR/not-supported.rs:79:9
-   |
-LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
-   = help: specify the types explicitly
-note: in edition 2024, the requirement `!: opaque::Trait` will fail
-  --> $DIR/not-supported.rs:79:28
-   |
-LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
-   |                            ^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
-
-error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/not-supported.rs:85:5: 85:24>::{synthetic#0}`
-  --> $DIR/not-supported.rs:86:25
-   |
-LL |         reuse to_reuse::opaque_ret;
-   |                         ^^^^^^^^^^
-   |
-note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
-  --> $DIR/not-supported.rs:86:25
-   |
-LL |         reuse to_reuse::opaque_ret;
-   |                         ^^^^^^^^^^
-   = note: ...which again requires computing type of `opaque::<impl at $DIR/not-supported.rs:85:5: 85:24>::{synthetic#0}`, completing the cycle
-note: cycle used when checking that `opaque::<impl at $DIR/not-supported.rs:85:5: 85:24>` is well-formed
-  --> $DIR/not-supported.rs:85:5
-   |
-LL |     impl ToReuse for u8 {
-   |     ^^^^^^^^^^^^^^^^^^^
-   = 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
-
-warning: this function depends on never type fallback being `()`
-  --> $DIR/not-supported.rs:73:9
-   |
-LL |         pub fn opaque_ret() -> impl Trait { unimplemented!() }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
-   = help: specify the types explicitly
-note: in edition 2024, the requirement `!: opaque::Trait` will fail
-  --> $DIR/not-supported.rs:73:32
-   |
-LL |         pub fn opaque_ret() -> impl Trait { unimplemented!() }
-   |                                ^^^^^^^^^^
-
-error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/not-supported.rs:88:5: 88:25>::{synthetic#0}`
-  --> $DIR/not-supported.rs:89:24
-   |
-LL |         reuse ToReuse::opaque_ret;
-   |                        ^^^^^^^^^^
-   |
-note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
-  --> $DIR/not-supported.rs:89:24
-   |
-LL |         reuse ToReuse::opaque_ret;
-   |                        ^^^^^^^^^^
-   = note: ...which again requires computing type of `opaque::<impl at $DIR/not-supported.rs:88:5: 88:25>::{synthetic#0}`, completing the cycle
-note: cycle used when checking that `opaque::<impl at $DIR/not-supported.rs:88:5: 88:25>` is well-formed
-  --> $DIR/not-supported.rs:88:5
-   |
-LL |     impl ToReuse for u16 {
-   |     ^^^^^^^^^^^^^^^^^^^^
-   = 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: recursive delegation is not supported yet
-  --> $DIR/not-supported.rs:102:22
-   |
-LL |         pub reuse to_reuse2::foo;
-   |                              --- callee defined here
-...
-LL |     reuse to_reuse1::foo;
-   |                      ^^^
-
-error: aborting due to 17 previous errors; 2 warnings emitted
-
-Some errors have detailed explanations: E0049, E0195, E0391.
-For more information about an error, try `rustc --explain E0049`.
diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs
new file mode 100644
index 00000000000..e57effff48d
--- /dev/null
+++ b/tests/ui/delegation/unsupported.rs
@@ -0,0 +1,57 @@
+#![feature(const_trait_impl)]
+#![feature(c_variadic)]
+#![feature(effects)]
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod opaque {
+    trait Trait {}
+    impl Trait for () {}
+
+    mod to_reuse {
+        use super::Trait;
+
+        pub fn opaque_ret() -> impl Trait { unimplemented!() }
+        //~^ warn: this function depends on never type fallback being `()`
+        //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    }
+
+    trait ToReuse {
+        fn opaque_ret() -> impl Trait { unimplemented!() }
+        //~^ warn: this function depends on never type fallback being `()`
+        //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    }
+
+    // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls.
+    impl ToReuse for u8 {
+        reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type
+    }
+    impl ToReuse for u16 {
+        reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type
+    }
+}
+
+mod recursive {
+    mod to_reuse1 {
+        pub mod to_reuse2 {
+            pub fn foo() {}
+        }
+
+        pub reuse to_reuse2::foo;
+    }
+
+    reuse to_reuse1::foo;
+    //~^ ERROR recursive delegation is not supported yet
+}
+
+mod effects {
+    #[const_trait]
+    trait Trait {
+        fn foo();
+    }
+
+    reuse Trait::foo;
+    //~^ ERROR delegation to a function with effect parameter is not supported yet
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr
new file mode 100644
index 00000000000..03ded300bb4
--- /dev/null
+++ b/tests/ui/delegation/unsupported.stderr
@@ -0,0 +1,95 @@
+error: using `#![feature(effects)]` without enabling next trait solver globally
+   |
+   = note: the next trait solver must be enabled globally for the effects feature to work correctly
+   = help: use `-Znext-solver` to enable
+
+warning: this function depends on never type fallback being `()`
+  --> $DIR/unsupported.rs:20:9
+   |
+LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the types explicitly
+note: in edition 2024, the requirement `!: opaque::Trait` will fail
+  --> $DIR/unsupported.rs:20:28
+   |
+LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
+   |                            ^^^^^^^^^^
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+
+error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}`
+  --> $DIR/unsupported.rs:27:25
+   |
+LL |         reuse to_reuse::opaque_ret;
+   |                         ^^^^^^^^^^
+   |
+note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
+  --> $DIR/unsupported.rs:27:25
+   |
+LL |         reuse to_reuse::opaque_ret;
+   |                         ^^^^^^^^^^
+   = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}`, completing the cycle
+note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>` is well-formed
+  --> $DIR/unsupported.rs:26:5
+   |
+LL |     impl ToReuse for u8 {
+   |     ^^^^^^^^^^^^^^^^^^^
+   = 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
+
+warning: this function depends on never type fallback being `()`
+  --> $DIR/unsupported.rs:14:9
+   |
+LL |         pub fn opaque_ret() -> impl Trait { unimplemented!() }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the types explicitly
+note: in edition 2024, the requirement `!: opaque::Trait` will fail
+  --> $DIR/unsupported.rs:14:32
+   |
+LL |         pub fn opaque_ret() -> impl Trait { unimplemented!() }
+   |                                ^^^^^^^^^^
+
+error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:29:5: 29:25>::{synthetic#0}`
+  --> $DIR/unsupported.rs:30:24
+   |
+LL |         reuse ToReuse::opaque_ret;
+   |                        ^^^^^^^^^^
+   |
+note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
+  --> $DIR/unsupported.rs:30:24
+   |
+LL |         reuse ToReuse::opaque_ret;
+   |                        ^^^^^^^^^^
+   = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:29:5: 29:25>::{synthetic#0}`, completing the cycle
+note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:29:5: 29:25>` is well-formed
+  --> $DIR/unsupported.rs:29:5
+   |
+LL |     impl ToReuse for u16 {
+   |     ^^^^^^^^^^^^^^^^^^^^
+   = 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: recursive delegation is not supported yet
+  --> $DIR/unsupported.rs:43:22
+   |
+LL |         pub reuse to_reuse2::foo;
+   |                              --- callee defined here
+...
+LL |     reuse to_reuse1::foo;
+   |                      ^^^
+
+error: delegation to a function with effect parameter is not supported yet
+  --> $DIR/unsupported.rs:53:18
+   |
+LL |         fn foo();
+   |         --------- callee defined here
+...
+LL |     reuse Trait::foo;
+   |                  ^^^
+
+error: aborting due to 5 previous errors; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0391`.