about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBryanskiy <ivakin.kir@gmail.com>2024-05-30 22:00:44 +0300
committerBryanskiy <ivakin.kir@gmail.com>2024-07-29 20:04:55 +0300
commitf2f9aab3806916105518ce8e4ccb143028ab81ff (patch)
tree7e9c52a26b2c4106267288e3035b6c4d5e824f92
parent80d8270d8488957f62fbf0df7a19dfe596be92ac (diff)
downloadrust-f2f9aab3806916105518ce8e4ccb143028ab81ff.tar.gz
rust-f2f9aab3806916105518ce8e4ccb143028ab81ff.zip
Delegation: support generics for delegation from free functions
-rw-r--r--compiler/rustc_ast_lowering/src/delegation.rs2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl3
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/delegation.rs259
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs94
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs5
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs15
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--tests/ui/delegation/explicit-paths.rs2
-rw-r--r--tests/ui/delegation/explicit-paths.stderr46
-rw-r--r--tests/ui/delegation/generics/free-fn-to-free-fn-pass.rs28
-rw-r--r--tests/ui/delegation/generics/free-fn-to-free-fn.rs27
-rw-r--r--tests/ui/delegation/generics/free-fn-to-free-fn.stderr54
-rw-r--r--tests/ui/delegation/generics/free-fn-to-trait-method-pass.rs30
-rw-r--r--tests/ui/delegation/generics/free-fn-to-trait-method.rs56
-rw-r--r--tests/ui/delegation/generics/free-fn-to-trait-method.stderr88
-rw-r--r--tests/ui/delegation/ice-issue-124347.rs3
-rw-r--r--tests/ui/delegation/ice-issue-124347.stderr15
-rw-r--r--tests/ui/delegation/not-supported.rs35
-rw-r--r--tests/ui/delegation/not-supported.stderr103
-rw-r--r--tests/ui/delegation/target-expr.rs5
-rw-r--r--tests/ui/delegation/target-expr.stderr43
24 files changed, 702 insertions, 233 deletions
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 378d98e5c34..6e8ff72cf87 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -33,7 +33,7 @@
 //! HIR ty lowering.
 //!
 //! Similarly generics, predicates and header are set to the "default" values.
-//! In case of discrepancy with callee function the `NotSupportedDelegation` error will
+//! In case of discrepancy with callee function the `UnsupportedDelegation` error will
 //! also be emitted during HIR ty lowering.
 
 use std::iter;
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 367f6e17e7f..bde94be6f51 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -341,8 +341,7 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation
 
 hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
 
-hir_analysis_not_supported_delegation =
-    {$descr} is not supported yet
+hir_analysis_not_supported_delegation = {$descr}
     .label = callee defined here
 
 hir_analysis_only_current_traits_adt = `{$name}` is not defined in the current crate
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 41ffb038341..80a65aa2988 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -10,6 +10,7 @@ use rustc_session::lint;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
+use crate::delegation::inherit_generics_for_delegation_item;
 use crate::middle::resolve_bound_vars as rbv;
 
 #[instrument(level = "debug", skip(tcx), ret)]
@@ -53,6 +54,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
         };
     }
 
+    // For a delegation item inherit generics from callee.
+    if let Some(sig_id) = tcx.hir().opt_delegation_sig_id(def_id)
+        && let Some(generics) = inherit_generics_for_delegation_item(tcx, def_id, sig_id)
+    {
+        return generics;
+    }
+
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
 
     let node = tcx.hir_node(hir_id);
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 783365bdacc..ae52dbd56f9 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -12,6 +12,7 @@ use rustc_span::{Span, DUMMY_SP};
 use crate::bounds::Bounds;
 use crate::collect::ItemCtxt;
 use crate::constrained_generic_params as cgp;
+use crate::delegation::inherit_predicates_for_delegation_item;
 use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason};
 
 /// Returns a list of all type predicates (explicit and implicit) for the definition with
@@ -114,6 +115,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         None => {}
     }
 
+    // For a delegation item inherit predicates from callee.
+    if let Some(sig_id) = tcx.hir().opt_delegation_sig_id(def_id)
+        && let Some(predicates) = inherit_predicates_for_delegation_item(tcx, def_id, sig_id)
+    {
+        return predicates;
+    }
+
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
     let node = tcx.hir_node(hir_id);
 
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
new file mode 100644
index 00000000000..e21ed55bce3
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -0,0 +1,259 @@
+use rustc_data_structures::fx::FxHashMap;
+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_type_ir::visit::TypeVisitableExt;
+
+type RemapTable = FxHashMap<u32, u32>;
+
+struct ParamIndexRemapper<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    remap_table: RemapTable,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamIndexRemapper<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if !ty.has_param() {
+            return ty;
+        }
+
+        if let ty::Param(param) = ty.kind()
+            && let Some(index) = self.remap_table.get(&param.index)
+        {
+            return Ty::new_param(self.tcx, *index, param.name);
+        }
+        ty.super_fold_with(self)
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        if let ty::ReEarlyParam(param) = r.kind()
+            && let Some(index) = self.remap_table.get(&param.index).copied()
+        {
+            return ty::Region::new_early_param(
+                self.tcx,
+                ty::EarlyParamRegion { index, name: param.name },
+            );
+        }
+        r
+    }
+
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        if let ty::ConstKind::Param(param) = ct.kind()
+            && let Some(idx) = self.remap_table.get(&param.index)
+        {
+            let param = ty::ParamConst::new(*idx, param.name);
+            return ty::Const::new_param(self.tcx, param);
+        }
+        ct.super_fold_with(self)
+    }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+enum FnKind {
+    Free,
+    AssocInherentImpl,
+    AssocTrait,
+    AssocTraitImpl,
+}
+
+fn fn_kind<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> FnKind {
+    debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn));
+
+    let parent = tcx.parent(def_id);
+    match tcx.def_kind(parent) {
+        DefKind::Trait => FnKind::AssocTrait,
+        DefKind::Impl { of_trait: true } => FnKind::AssocTraitImpl,
+        DefKind::Impl { of_trait: false } => FnKind::AssocInherentImpl,
+        _ => FnKind::Free,
+    }
+}
+
+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 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)
+        }
+        // FIXME(fn_delegation): Only `Self` param supported here.
+        (FnKind::AssocTraitImpl, FnKind::AssocTrait)
+        | (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))
+        }
+        _ => ty::GenericArgs::identity_for_item(tcx, sig_id),
+    }
+}
+
+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;
+    }
+
+    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());
+
+    // Lifetimes go first.
+    own_params.sort_by_key(|key| key.kind.is_ty_or_const());
+
+    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;
+        }
+    }
+
+    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,
+    })
+}
+
+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);
+    let args = create_generic_args(tcx, def_id, 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));
+
+    Some(ty::GenericPredicates {
+        parent: None,
+        predicates: tcx.arena.alloc_from_iter(preds),
+        effects_min_tys: ty::List::empty(),
+    })
+}
+
+fn check_constraints<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    sig_id: DefId,
+) -> Result<(), ErrorGuaranteed> {
+    let mut ret = Ok(());
+
+    let mut emit = |descr| {
+        ret = Err(tcx.dcx().emit_err(crate::errors::UnsupportedDelegation {
+            span: tcx.def_span(def_id),
+            descr,
+            callee_span: tcx.def_span(sig_id),
+        }));
+    };
+
+    if tcx.has_host_param(sig_id) {
+        emit("delegation to a function with effect parameter is not supported yet");
+    }
+
+    if let Some(local_sig_id) = sig_id.as_local()
+        && tcx.hir().opt_delegation_sig_id(local_sig_id).is_some()
+    {
+        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
+}
+
+pub(crate) fn inherit_sig_for_delegation_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> &'tcx [Ty<'tcx>] {
+    let sig_id = tcx.hir().delegation_sig_id(def_id);
+    let caller_sig = tcx.fn_sig(sig_id);
+    if let Err(err) = check_constraints(tcx, def_id, sig_id) {
+        let sig_len = caller_sig.instantiate_identity().skip_binder().inputs().len() + 1;
+        let err_type = Ty::new_error(tcx, err);
+        return tcx.arena.alloc_from_iter((0..sig_len).map(|_| err_type));
+    }
+    let args = create_generic_args(tcx, def_id, sig_id);
+
+    // Bound vars are also inherited from `sig_id`.
+    // They will be rebound later in `lower_fn_ty`.
+    let sig = caller_sig.instantiate(tcx, args).skip_binder();
+    let sig_iter = sig.inputs().iter().cloned().chain(std::iter::once(sig.output()));
+    tcx.arena.alloc_from_iter(sig_iter)
+}
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index b1ac973ef2e..7034735aec0 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1575,7 +1575,7 @@ pub struct RefOfMutStatic<'a> {
 
 #[derive(Diagnostic)]
 #[diag(hir_analysis_not_supported_delegation)]
-pub struct NotSupportedDelegation<'a> {
+pub struct UnsupportedDelegation<'a> {
     #[primary_span]
     pub span: Span,
     pub descr: &'a str,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 52b2411cd37..d865357b829 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2007,93 +2007,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         self.lower_ty_common(hir_ty, false, true)
     }
 
-    fn check_delegation_constraints(&self, sig_id: DefId, span: Span, emit: bool) -> bool {
-        let mut error_occured = false;
-        let sig_span = self.tcx().def_span(sig_id);
-        let mut try_emit = |descr| {
-            if emit {
-                self.dcx().emit_err(crate::errors::NotSupportedDelegation {
-                    span,
-                    descr,
-                    callee_span: sig_span,
-                });
-            }
-            error_occured = true;
-        };
-
-        if let Some(node) = self.tcx().hir().get_if_local(sig_id)
-            && let Some(decl) = node.fn_decl()
-            && let hir::FnRetTy::Return(ty) = decl.output
-            && let hir::TyKind::InferDelegation(_, _) = ty.kind
-        {
-            try_emit("recursive delegation");
-        }
-
-        let sig_generics = self.tcx().generics_of(sig_id);
-        let parent = self.tcx().local_parent(self.item_def_id());
-        let parent_generics = self.tcx().generics_of(parent);
-
-        let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize;
-        let sig_has_self = sig_generics.has_self as usize;
-
-        if sig_generics.count() > sig_has_self || parent_generics.count() > parent_is_trait {
-            try_emit("delegation with early bound generics");
-        }
-
-        // There is no way to instantiate `Self` param for caller if
-        // 1. callee is a trait method
-        // 2. delegation item isn't an associative item
-        if let DefKind::AssocFn = self.tcx().def_kind(sig_id)
-            && let DefKind::Fn = self.tcx().def_kind(self.item_def_id())
-            && self.tcx().associated_item(sig_id).container
-                == ty::AssocItemContainer::TraitContainer
-        {
-            try_emit("delegation to a trait method from a free function");
-        }
-
-        error_occured
-    }
-
-    fn lower_delegation_ty(
-        &self,
-        sig_id: DefId,
-        idx: hir::InferDelegationKind,
-        span: Span,
-    ) -> Ty<'tcx> {
-        if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output)
-        {
-            let e = self.dcx().span_delayed_bug(span, "not supported delegation case");
-            return Ty::new_error(self.tcx(), e);
-        };
-        let sig = self.tcx().fn_sig(sig_id);
-        let sig_generics = self.tcx().generics_of(sig_id);
-
-        let parent = self.tcx().local_parent(self.item_def_id());
-        let parent_def_kind = self.tcx().def_kind(parent);
-
-        let sig = if let DefKind::Impl { .. } = parent_def_kind
-            && sig_generics.has_self
-        {
-            // Generic params can't be here except the trait self type.
-            // They are not supported yet.
-            assert_eq!(sig_generics.count(), 1);
-            assert_eq!(self.tcx().generics_of(parent).count(), 0);
-
-            let self_ty = self.tcx().type_of(parent).instantiate_identity();
-            let generic_self_ty = ty::GenericArg::from(self_ty);
-            let args = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
-            sig.instantiate(self.tcx(), args)
-        } else {
-            sig.instantiate_identity()
-        };
-
-        // Bound vars are also inherited from `sig_id`.
-        // They will be rebound later in `lower_fn_ty`.
-        let sig = sig.skip_binder();
-
+    fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
+        let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id());
         match idx {
-            hir::InferDelegationKind::Input(id) => sig.inputs()[id],
-            hir::InferDelegationKind::Output => sig.output(),
+            hir::InferDelegationKind::Input(idx) => delegation_sig[idx],
+            hir::InferDelegationKind::Output => *delegation_sig.last().unwrap(),
         }
     }
 
@@ -2110,9 +2028,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let tcx = self.tcx();
 
         let result_ty = match &hir_ty.kind {
-            hir::TyKind::InferDelegation(sig_id, idx) => {
-                self.lower_delegation_ty(*sig_id, *idx, hir_ty.span)
-            }
+            hir::TyKind::InferDelegation(_, idx) => self.lower_delegation_ty(*idx),
             hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)),
             hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl),
             hir::TyKind::Ref(region, mt) => {
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 8154e7cfd36..061db14ad0a 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -83,6 +83,7 @@ pub mod autoderef;
 mod bounds;
 mod check_unused;
 mod coherence;
+mod delegation;
 pub mod hir_ty_lowering;
 // FIXME: This module shouldn't be public.
 pub mod collect;
@@ -146,6 +147,10 @@ pub fn provide(providers: &mut Providers) {
     variance::provide(providers);
     outlives::provide(providers);
     hir_wf_check::provide(providers);
+    *providers = Providers {
+        inherit_sig_for_delegation_item: delegation::inherit_sig_for_delegation_item,
+        ..*providers
+    };
 }
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 1c223481a07..1705c016437 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -746,6 +746,21 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    pub fn opt_delegation_sig_id(self, def_id: LocalDefId) -> Option<DefId> {
+        if let Some(ret) = self.get_fn_output(def_id)
+            && let FnRetTy::Return(ty) = ret
+            && let TyKind::InferDelegation(sig_id, _) = ty.kind
+        {
+            return Some(sig_id);
+        }
+        None
+    }
+
+    #[inline]
+    pub fn delegation_sig_id(self, def_id: LocalDefId) -> DefId {
+        self.opt_delegation_sig_id(def_id).unwrap()
+    }
+
     #[inline]
     fn opt_ident(self, id: HirId) -> Option<Ident> {
         match self.tcx.hir_node(id) {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index ff8ee9f6456..c22c2e985ab 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1722,6 +1722,10 @@ rustc_queries! {
         desc { |tcx| "getting the native library for `{}`", tcx.def_path_str(def_id) }
     }
 
+    query inherit_sig_for_delegation_item(def_id: LocalDefId) -> &'tcx [Ty<'tcx>] {
+        desc { "inheriting delegation signature" }
+    }
+
     /// Does lifetime resolution on items. Importantly, we can't resolve
     /// lifetimes directly on things like trait methods, because of trait params.
     /// See `rustc_resolve::late::lifetimes` for details.
diff --git a/tests/ui/delegation/explicit-paths.rs b/tests/ui/delegation/explicit-paths.rs
index d42e305b252..3b0454eb524 100644
--- a/tests/ui/delegation/explicit-paths.rs
+++ b/tests/ui/delegation/explicit-paths.rs
@@ -22,9 +22,7 @@ mod fn_to_other {
     use super::*;
 
     reuse Trait::foo1;
-    //~^ ERROR delegation to a trait method from a free function is not supported yet
     reuse <S as Trait>::foo2;
-    //~^ ERROR delegation to a trait method from a free function is not supported yet
     reuse to_reuse::foo3;
     reuse S::foo4;
     //~^ ERROR cannot find function `foo4` in `S`
diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr
index b5afe19f878..8098ea8c54f 100644
--- a/tests/ui/delegation/explicit-paths.stderr
+++ b/tests/ui/delegation/explicit-paths.stderr
@@ -1,5 +1,5 @@
 error[E0407]: method `foo3` is not a member of trait `Trait`
-  --> $DIR/explicit-paths.rs:51:9
+  --> $DIR/explicit-paths.rs:49:9
    |
 LL |         reuse to_reuse::foo3;
    |         ^^^^^^^^^^^^^^^^----^
@@ -8,7 +8,7 @@ LL |         reuse to_reuse::foo3;
    |         not a member of trait `Trait`
 
 error[E0407]: method `foo4` is not a member of trait `Trait`
-  --> $DIR/explicit-paths.rs:53:9
+  --> $DIR/explicit-paths.rs:51:9
    |
 LL |         reuse F::foo4 { &self.0 }
    |         ^^^^^^^^^----^^^^^^^^^^^^
@@ -17,49 +17,49 @@ LL |         reuse F::foo4 { &self.0 }
    |         not a member of trait `Trait`
 
 error[E0425]: cannot find function `foo4` in `S`
-  --> $DIR/explicit-paths.rs:29:14
+  --> $DIR/explicit-paths.rs:27:14
    |
 LL |     reuse S::foo4;
    |              ^^^^ not found in `S`
 
 error[E0425]: cannot find function `foo4` in `F`
-  --> $DIR/explicit-paths.rs:40:18
+  --> $DIR/explicit-paths.rs:38:18
    |
 LL |         reuse F::foo4 { &self.0 }
    |                  ^^^^ not found in `F`
    |
 note: function `fn_to_other::foo4` exists but is inaccessible
-  --> $DIR/explicit-paths.rs:29:5
+  --> $DIR/explicit-paths.rs:27:5
    |
 LL |     reuse S::foo4;
    |     ^^^^^^^^^^^^^^ not accessible
 
 error[E0425]: cannot find function `foo4` in `F`
-  --> $DIR/explicit-paths.rs:53:18
+  --> $DIR/explicit-paths.rs:51:18
    |
 LL |         reuse F::foo4 { &self.0 }
    |                  ^^^^ not found in `F`
    |
 note: function `fn_to_other::foo4` exists but is inaccessible
-  --> $DIR/explicit-paths.rs:29:5
+  --> $DIR/explicit-paths.rs:27:5
    |
 LL |     reuse S::foo4;
    |     ^^^^^^^^^^^^^^ not accessible
 
 error[E0425]: cannot find function `foo4` in `F`
-  --> $DIR/explicit-paths.rs:67:18
+  --> $DIR/explicit-paths.rs:65:18
    |
 LL |         reuse F::foo4 { &F }
    |                  ^^^^ not found in `F`
    |
 note: function `fn_to_other::foo4` exists but is inaccessible
-  --> $DIR/explicit-paths.rs:29:5
+  --> $DIR/explicit-paths.rs:27:5
    |
 LL |     reuse S::foo4;
    |     ^^^^^^^^^^^^^^ not accessible
 
 error[E0119]: conflicting implementations of trait `Trait` for type `S`
-  --> $DIR/explicit-paths.rs:76:5
+  --> $DIR/explicit-paths.rs:74:5
    |
 LL |     impl Trait for S {
    |     ---------------- first implementation here
@@ -67,26 +67,8 @@ LL |     impl Trait for S {
 LL |     impl Trait for S {
    |     ^^^^^^^^^^^^^^^^ conflicting implementation for `S`
 
-error: delegation to a trait method from a free function is not supported yet
-  --> $DIR/explicit-paths.rs:24:18
-   |
-LL |     fn foo1(&self, x: i32) -> i32 { x }
-   |     ----------------------------- callee defined here
-...
-LL |     reuse Trait::foo1;
-   |                  ^^^^
-
-error: delegation to a trait method from a free function is not supported yet
-  --> $DIR/explicit-paths.rs:26:25
-   |
-LL |     fn foo2(x: i32) -> i32 { x }
-   |     ---------------------- callee defined here
-...
-LL |     reuse <S as Trait>::foo2;
-   |                         ^^^^
-
 error[E0308]: mismatched types
-  --> $DIR/explicit-paths.rs:63:36
+  --> $DIR/explicit-paths.rs:61:36
    |
 LL |     trait Trait2 : Trait {
    |     -------------------- found this type parameter
@@ -104,7 +86,7 @@ LL |     fn foo1(&self, x: i32) -> i32 { x }
    |        ^^^^ -----
 
 error[E0277]: the trait bound `S2: Trait` is not satisfied
-  --> $DIR/explicit-paths.rs:78:16
+  --> $DIR/explicit-paths.rs:76:16
    |
 LL |         reuse <S2 as Trait>::foo1;
    |                ^^ the trait `Trait` is not implemented for `S2`
@@ -114,7 +96,7 @@ LL |         reuse <S2 as Trait>::foo1;
              S
 
 error[E0308]: mismatched types
-  --> $DIR/explicit-paths.rs:78:30
+  --> $DIR/explicit-paths.rs:76:30
    |
 LL |         reuse <S2 as Trait>::foo1;
    |                              ^^^^
@@ -130,7 +112,7 @@ note: method defined here
 LL |     fn foo1(&self, x: i32) -> i32 { x }
    |        ^^^^ -----
 
-error: aborting due to 12 previous errors
+error: aborting due to 10 previous errors
 
 Some errors have detailed explanations: E0119, E0277, E0308, E0407, E0425.
 For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn-pass.rs b/tests/ui/delegation/generics/free-fn-to-free-fn-pass.rs
new file mode 100644
index 00000000000..625bbdd758c
--- /dev/null
+++ b/tests/ui/delegation/generics/free-fn-to-free-fn-pass.rs
@@ -0,0 +1,28 @@
+//@ run-pass
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod to_reuse {
+    pub fn types<T, U>(x: U, y: T) -> (T, U) {
+        (y, x)
+    }
+    pub fn late<'a, 'b>(x: &'a u8, y: &'b u8) -> u8 {
+        *x + *y
+    }
+    pub fn early<'a: 'a>(x: &'a str) -> &'a str {
+        x
+    }
+}
+
+reuse to_reuse::types;
+reuse to_reuse::late;
+reuse to_reuse::early;
+
+fn main() {
+    assert_eq!(types(0, "str"), ("str", 0));
+    assert_eq!(late(&1u8, &2u8), 3);
+    {
+        let s: &'static str = "hello world";
+        assert_eq!(early::<'static>(s), "hello world");
+    }
+}
diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn.rs b/tests/ui/delegation/generics/free-fn-to-free-fn.rs
new file mode 100644
index 00000000000..3741ad66485
--- /dev/null
+++ b/tests/ui/delegation/generics/free-fn-to-free-fn.rs
@@ -0,0 +1,27 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod to_reuse {
+    pub fn consts<const N: i32>() -> i32 {
+        N
+    }
+    pub fn late<'a>(x: &'a u8) -> u8 {
+        *x
+    }
+    pub fn bounds<T: Clone>(_: T) {}
+}
+
+// FIXME(fn_delegation): this is supposed to work eventually
+reuse to_reuse::consts;
+//~^ ERROR  type annotations needed
+reuse to_reuse::late;
+reuse to_reuse::bounds;
+
+fn main() {
+    late::<'static>(&0u8);
+    //~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+
+    struct S;
+    bounds(S);
+    //~^ ERROR the trait bound `S: Clone` is not satisfied
+}
diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn.stderr b/tests/ui/delegation/generics/free-fn-to-free-fn.stderr
new file mode 100644
index 00000000000..5ba56ce1718
--- /dev/null
+++ b/tests/ui/delegation/generics/free-fn-to-free-fn.stderr
@@ -0,0 +1,54 @@
+error[E0284]: type annotations needed
+  --> $DIR/free-fn-to-free-fn.rs:15:17
+   |
+LL | reuse to_reuse::consts;
+   |                 ^^^^^^ cannot infer the value of the const parameter `N` declared on the function `consts`
+   |
+note: required by a const generic parameter in `to_reuse::consts`
+  --> $DIR/free-fn-to-free-fn.rs:5:19
+   |
+LL |     pub fn consts<const N: i32>() -> i32 {
+   |                   ^^^^^^^^^^^^ required by this const generic parameter in `consts`
+help: consider specifying the generic argument
+   |
+LL | reuse to_reuse::consts::<N>;
+   |                       +++++
+
+error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/free-fn-to-free-fn.rs:21:12
+   |
+LL |     late::<'static>(&0u8);
+   |            ^^^^^^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/free-fn-to-free-fn.rs:8:17
+   |
+LL |     pub fn late<'a>(x: &'a u8) -> u8 {
+   |                 ^^
+
+error[E0277]: the trait bound `S: Clone` is not satisfied
+  --> $DIR/free-fn-to-free-fn.rs:25:12
+   |
+LL |     bounds(S);
+   |     ------ ^ the trait `Clone` is not implemented for `S`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `bounds`
+  --> $DIR/free-fn-to-free-fn.rs:11:22
+   |
+LL |     pub fn bounds<T: Clone>(_: T) {}
+   |                      ^^^^^ required by this bound in `bounds`
+...
+LL | reuse to_reuse::bounds;
+   |                 ------ required by a bound in this function
+help: consider annotating `S` with `#[derive(Clone)]`
+   |
+LL +     #[derive(Clone)]
+LL |     struct S;
+   |
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0284, E0794.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/delegation/generics/free-fn-to-trait-method-pass.rs b/tests/ui/delegation/generics/free-fn-to-trait-method-pass.rs
new file mode 100644
index 00000000000..f7b7c09e2ca
--- /dev/null
+++ b/tests/ui/delegation/generics/free-fn-to-trait-method-pass.rs
@@ -0,0 +1,30 @@
+//@ run-pass
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod types {
+    pub trait Trait<T> {
+        fn foo<U>(&self, x: U, y: T) -> (T, U) {(y, x)}
+    }
+    impl<T> Trait<T> for u8 {}
+}
+
+mod types_and_lifetimes {
+    pub trait Trait<'a, T> {
+        fn foo<'b, U>(&self, _: &'b U, _: &'a T) -> bool {
+            true
+        }
+    }
+    impl<'a, T> Trait<'a, T> for u8 {}
+}
+
+reuse types::Trait::foo as types;
+reuse types_and_lifetimes::Trait::foo as types_and_lifetimes;
+
+fn main() {
+    assert_eq!(types(&2, "str", 1), (1, "str"));
+
+    struct T;
+    struct U;
+    assert_eq!(types_and_lifetimes::<u8, T, U>(&1, &U, &T), true);
+}
diff --git a/tests/ui/delegation/generics/free-fn-to-trait-method.rs b/tests/ui/delegation/generics/free-fn-to-trait-method.rs
new file mode 100644
index 00000000000..70be1a4ace7
--- /dev/null
+++ b/tests/ui/delegation/generics/free-fn-to-trait-method.rs
@@ -0,0 +1,56 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod default_param {
+    pub trait Trait<T = u32> {
+        fn foo(&self, _: T) {}
+    }
+
+    impl<T> Trait<T> for u8 {}
+}
+
+mod types_and_lifetimes {
+    pub trait Trait<'a, T> {
+        fn foo<'b: 'b>(&'a self, x: &'b T) {
+            loop {}
+        }
+    }
+    impl<'a, T> Trait<'a, T> for u8 {}
+}
+
+mod bounds {
+    pub trait Trait<T> {
+        fn foo<U: Clone>(&self, t: T, u: U) where T: Copy {}
+    }
+
+    impl<T> Trait<T> for u8 {}
+}
+
+mod generic_arguments {
+    trait Trait<T> {
+        fn foo<U>(&self, _: U, _: T) {}
+    }
+
+    impl<T> Trait<T> for u8 {}
+
+    reuse Trait::<_>::foo::<i32> as generic_arguments1;
+    //~^ ERROR mismatched types
+    reuse <u8 as Trait<_>>::foo as generic_arguments2;
+    //~^ ERROR mismatched types
+    reuse <_ as Trait<_>>::foo as generic_arguments3; // OK
+}
+
+reuse default_param::Trait::foo as default_param;
+reuse types_and_lifetimes::Trait::foo as types_and_lifetimes;
+reuse bounds::Trait::foo as bounds;
+
+fn main() {
+    default_param(&0u8, "hello world"); // OK, default params are not substituted
+    types_and_lifetimes::<'static, 'static, _, _>(&0u8, &0u16); // OK, lifetimes go first
+
+    struct S;
+    struct U;
+    bounds(&0u8, S, U);
+    //~^ ERROR the trait bound `S: Copy` is not satisfied
+    //~| ERROR the trait bound `U: Clone` is not satisfied
+}
diff --git a/tests/ui/delegation/generics/free-fn-to-trait-method.stderr b/tests/ui/delegation/generics/free-fn-to-trait-method.stderr
new file mode 100644
index 00000000000..d8299d00c7e
--- /dev/null
+++ b/tests/ui/delegation/generics/free-fn-to-trait-method.stderr
@@ -0,0 +1,88 @@
+error[E0308]: mismatched types
+  --> $DIR/free-fn-to-trait-method.rs:36:23
+   |
+LL |         fn foo<U>(&self, _: U, _: T) {}
+   |                - found this type parameter
+...
+LL |     reuse Trait::<_>::foo::<i32> as generic_arguments1;
+   |                       ^^^
+   |                       |
+   |                       expected `i32`, found type parameter `U`
+   |                       arguments to this function are incorrect
+   |
+   = note:        expected type `i32`
+           found type parameter `U`
+note: method defined here
+  --> $DIR/free-fn-to-trait-method.rs:31:12
+   |
+LL |         fn foo<U>(&self, _: U, _: T) {}
+   |            ^^^           ----
+
+error[E0308]: mismatched types
+  --> $DIR/free-fn-to-trait-method.rs:38:29
+   |
+LL |     trait Trait<T> {
+   |     -------------- found this type parameter
+...
+LL |     reuse <u8 as Trait<_>>::foo as generic_arguments2;
+   |                             ^^^
+   |                             |
+   |                             expected `&u8`, found `&Self`
+   |                             arguments to this function are incorrect
+   |
+   = note: expected reference `&u8`
+              found reference `&Self`
+note: method defined here
+  --> $DIR/free-fn-to-trait-method.rs:31:12
+   |
+LL |         fn foo<U>(&self, _: U, _: T) {}
+   |            ^^^    -----
+
+error[E0277]: the trait bound `S: Copy` is not satisfied
+  --> $DIR/free-fn-to-trait-method.rs:53:18
+   |
+LL |     bounds(&0u8, S, U);
+   |     ------       ^ the trait `Copy` is not implemented for `S`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `bounds`
+  --> $DIR/free-fn-to-trait-method.rs:23:54
+   |
+LL |         fn foo<U: Clone>(&self, t: T, u: U) where T: Copy {}
+   |                                                      ^^^^ required by this bound in `bounds`
+...
+LL | reuse bounds::Trait::foo as bounds;
+   |                             ------ required by a bound in this function
+help: consider annotating `S` with `#[derive(Copy)]`
+   |
+LL +     #[derive(Copy)]
+LL |     struct S;
+   |
+
+error[E0277]: the trait bound `U: Clone` is not satisfied
+  --> $DIR/free-fn-to-trait-method.rs:53:21
+   |
+LL |     bounds(&0u8, S, U);
+   |     ------          ^ the trait `Clone` is not implemented for `U`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `bounds`
+  --> $DIR/free-fn-to-trait-method.rs:23:19
+   |
+LL |         fn foo<U: Clone>(&self, t: T, u: U) where T: Copy {}
+   |                   ^^^^^ required by this bound in `bounds`
+...
+LL | reuse bounds::Trait::foo as bounds;
+   |                             ------ required by a bound in this function
+help: consider annotating `U` with `#[derive(Clone)]`
+   |
+LL +     #[derive(Clone)]
+LL |     struct U;
+   |
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs
index 82a96055099..3bfae8face5 100644
--- a/tests/ui/delegation/ice-issue-124347.rs
+++ b/tests/ui/delegation/ice-issue-124347.rs
@@ -6,7 +6,8 @@ trait Trait {
     //~^ ERROR recursive delegation is not supported yet
 }
 
+// FIXME(fn_delegation): `recursive delegation` error should be emitted here
 reuse foo;
-//~^ ERROR recursive delegation is not supported yet
+//~^ ERROR cycle detected when computing generics of `foo`
 
 fn main() {}
diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr
index 5a3f4525d29..87dd75ffec8 100644
--- a/tests/ui/delegation/ice-issue-124347.stderr
+++ b/tests/ui/delegation/ice-issue-124347.stderr
@@ -4,11 +4,20 @@ error: recursive delegation is not supported yet
 LL |     reuse Trait::foo { &self.0 }
    |                  ^^^ callee defined here
 
-error: recursive delegation is not supported yet
-  --> $DIR/ice-issue-124347.rs:9:7
+error[E0391]: cycle detected when computing generics of `foo`
+  --> $DIR/ice-issue-124347.rs:10:7
+   |
+LL | reuse foo;
+   |       ^^^
+   |
+   = note: ...which immediately requires computing generics of `foo` again
+note: cycle used when checking that `foo` is well-formed
+  --> $DIR/ice-issue-124347.rs:10:7
    |
 LL | reuse foo;
-   |       ^^^ callee defined here
+   |       ^^^
+   = 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 2 previous errors
 
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs
index 25d7a4cb895..5701cc6055d 100644
--- a/tests/ui/delegation/not-supported.rs
+++ b/tests/ui/delegation/not-supported.rs
@@ -1,4 +1,6 @@
+#![feature(const_trait_impl)]
 #![feature(c_variadic)]
+#![feature(effects)]
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
 
@@ -14,9 +16,9 @@ mod generics {
         fn foo3<'a: 'a>(_: &'a u32) {}
 
         reuse GenericTrait::bar;
-        //~^ ERROR delegation with early bound generics is not supported yet
+        //~^ ERROR early bound generics are not supported for associated delegation items
         reuse GenericTrait::bar1;
-        //~^ ERROR delegation with early bound generics is not supported yet
+        //~^ ERROR early bound generics are not supported for associated delegation items
     }
 
     struct F;
@@ -27,37 +29,37 @@ mod generics {
 
     impl<T> GenericTrait<T> for S {
         reuse <F as GenericTrait<T>>::bar { &self.0 }
-        //~^ ERROR delegation with early bound generics is not supported yet
+        //~^ ERROR early bound generics are not supported for associated delegation items
         reuse GenericTrait::<T>::bar1;
-        //~^ ERROR delegation with early bound generics is not supported yet
+        //~^ ERROR early bound generics are not supported for associated delegation items
     }
 
     impl GenericTrait<()> for () {
         reuse GenericTrait::bar { &F }
-        //~^ ERROR delegation with early bound generics is not supported yet
+        //~^ ERROR early bound generics are not supported for associated delegation items
         reuse GenericTrait::bar1;
-        //~^ ERROR delegation with early bound generics is not supported yet
+        //~^ ERROR early bound generics are not supported for associated delegation items
     }
 
     impl Trait for &S {
         reuse Trait::foo;
-        //~^ ERROR delegation with early bound generics is not supported yet
+        //~^ 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 delegation with early bound generics is not supported yet
+        //~^ 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 delegation with early bound generics is not supported yet
+        //~^ ERROR early bound generics are not supported for associated delegation items
         //~| ERROR lifetime parameters or bounds on method `foo3` do not match the trait declaration
     }
 
     struct GenericS<T>(T);
     impl<T> Trait for GenericS<T> {
         reuse Trait::foo { &self.0 }
-        //~^ ERROR delegation with early bound generics is not supported yet
+        //~^ ERROR early bound generics are not supported for associated delegation items
     }
 }
 
@@ -68,13 +70,10 @@ mod opaque {
     mod to_reuse {
         use super::Trait;
 
-        pub fn opaque_arg(_: impl Trait) -> i32 { 0 }
         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!
     }
-    reuse to_reuse::opaque_arg;
-    //~^ ERROR delegation with early bound generics is not supported yet
 
     trait ToReuse {
         fn opaque_ret() -> impl Trait { unimplemented!() }
@@ -104,4 +103,14 @@ mod recursive {
     //~^ 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
index 4ce01fd5d88..e7ba9fc6719 100644
--- a/tests/ui/delegation/not-supported.stderr
+++ b/tests/ui/delegation/not-supported.stderr
@@ -1,5 +1,10 @@
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:16:29
+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
@@ -7,8 +12,8 @@ LL |         fn bar(&self, x: T) -> T { x }
 LL |         reuse GenericTrait::bar;
    |                             ^^^
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:18:29
+error: early bound generics are not supported for associated delegation items
+  --> $DIR/not-supported.rs:20:29
    |
 LL |         fn bar1() {}
    |         --------- callee defined here
@@ -16,8 +21,8 @@ LL |         fn bar1() {}
 LL |         reuse GenericTrait::bar1;
    |                             ^^^^
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:29:39
+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
@@ -25,8 +30,8 @@ LL |         fn bar(&self, x: T) -> T { x }
 LL |         reuse <F as GenericTrait<T>>::bar { &self.0 }
    |                                       ^^^
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:31:34
+error: early bound generics are not supported for associated delegation items
+  --> $DIR/not-supported.rs:33:34
    |
 LL |         fn bar1() {}
    |         --------- callee defined here
@@ -34,8 +39,8 @@ LL |         fn bar1() {}
 LL |         reuse GenericTrait::<T>::bar1;
    |                                  ^^^^
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:36:29
+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
@@ -43,8 +48,8 @@ LL |         fn bar(&self, x: T) -> T { x }
 LL |         reuse GenericTrait::bar { &F }
    |                             ^^^
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:38:29
+error: early bound generics are not supported for associated delegation items
+  --> $DIR/not-supported.rs:40:29
    |
 LL |         fn bar1() {}
    |         --------- callee defined here
@@ -52,8 +57,8 @@ LL |         fn bar1() {}
 LL |         reuse GenericTrait::bar1;
    |                             ^^^^
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:43:22
+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
@@ -62,7 +67,7 @@ LL |         reuse Trait::foo;
    |                      ^^^
 
 error[E0049]: method `foo2` has 0 type parameters but its trait declaration has 1 type parameter
-  --> $DIR/not-supported.rs:49:22
+  --> $DIR/not-supported.rs:51:22
    |
 LL |         fn foo2<T>(&self, x: T) -> T { x }
    |                 - expected 1 type parameter
@@ -70,8 +75,8 @@ LL |         fn foo2<T>(&self, x: T) -> T { x }
 LL |         reuse Trait::foo2 { &self.0 }
    |                      ^^^^ found 0 type parameters
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:52:29
+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
@@ -80,7 +85,7 @@ LL |         reuse <F as Trait>::foo3;
    |                             ^^^^
 
 error[E0195]: lifetime parameters or bounds on method `foo3` do not match the trait declaration
-  --> $DIR/not-supported.rs:52:29
+  --> $DIR/not-supported.rs:54:29
    |
 LL |         fn foo3<'a: 'a>(_: &'a u32) {}
    |                -------- lifetimes in impl do not match this method in trait
@@ -88,8 +93,17 @@ LL |         fn foo3<'a: 'a>(_: &'a u32) {}
 LL |         reuse <F as Trait>::foo3;
    |                             ^^^^ lifetimes do not match method in trait
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:59:22
+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
@@ -97,8 +111,8 @@ LL |         fn foo(&self, x: i32) -> i32 { x }
 LL |         reuse Trait::foo { &self.0 }
    |                      ^^^
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:49:22
+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
@@ -106,17 +120,8 @@ LL |         fn foo2<T>(&self, x: T) -> T { x }
 LL |         reuse Trait::foo2 { &self.0 }
    |                      ^^^^
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/not-supported.rs:76:21
-   |
-LL |         pub fn opaque_arg(_: impl Trait) -> i32 { 0 }
-   |         --------------------------------------- callee defined here
-...
-LL |     reuse to_reuse::opaque_arg;
-   |                     ^^^^^^^^^^
-
 warning: this function depends on never type fallback being `()`
-  --> $DIR/not-supported.rs:80:9
+  --> $DIR/not-supported.rs:79:9
    |
 LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -125,33 +130,33 @@ LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
    = 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:80:28
+  --> $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:86:5: 86:24>::{synthetic#0}`
-  --> $DIR/not-supported.rs:87:25
+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:87:25
+  --> $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:86:5: 86:24>::{synthetic#0}`, completing the cycle
-note: cycle used when checking that `opaque::<impl at $DIR/not-supported.rs:86:5: 86:24>` is well-formed
-  --> $DIR/not-supported.rs:86:5
+   = 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:72:9
+  --> $DIR/not-supported.rs:73:9
    |
 LL |         pub fn opaque_ret() -> impl Trait { unimplemented!() }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -160,32 +165,32 @@ LL |         pub fn opaque_ret() -> impl Trait { unimplemented!() }
    = 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:72:32
+  --> $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:89:5: 89:25>::{synthetic#0}`
-  --> $DIR/not-supported.rs:90:24
+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:90:24
+  --> $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:89:5: 89:25>::{synthetic#0}`, completing the cycle
-note: cycle used when checking that `opaque::<impl at $DIR/not-supported.rs:89:5: 89:25>` is well-formed
-  --> $DIR/not-supported.rs:89:5
+   = 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:103:22
+  --> $DIR/not-supported.rs:102:22
    |
 LL |         pub reuse to_reuse2::foo;
    |                              --- callee defined here
@@ -193,7 +198,7 @@ LL |         pub reuse to_reuse2::foo;
 LL |     reuse to_reuse1::foo;
    |                      ^^^
 
-error: aborting due to 16 previous errors; 2 warnings emitted
+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/target-expr.rs b/tests/ui/delegation/target-expr.rs
index fd7ea943b9d..f766ca7356a 100644
--- a/tests/ui/delegation/target-expr.rs
+++ b/tests/ui/delegation/target-expr.rs
@@ -14,9 +14,7 @@ fn foo(x: i32) -> i32 { x }
 
 fn bar<T: Default>(_: T) {
     reuse Trait::static_method {
-    //~^ ERROR delegation to a trait method from a free function is not supported yet
-    //~| ERROR delegation with early bound generics is not supported yet
-    //~| ERROR mismatched types
+    //~^ ERROR mismatched types
         let _ = T::Default();
         //~^ ERROR can't use generic parameters from outer item
     }
@@ -25,7 +23,6 @@ fn bar<T: Default>(_: T) {
 fn main() {
     let y = 0;
     reuse <S as Trait>::static_method {
-    //~^ ERROR delegation to a trait method from a free function is not supported yet
         let x = y;
         //~^ ERROR can't capture dynamic environment in a fn item
         foo(self);
diff --git a/tests/ui/delegation/target-expr.stderr b/tests/ui/delegation/target-expr.stderr
index b30f0c474c6..f5556bf9f45 100644
--- a/tests/ui/delegation/target-expr.stderr
+++ b/tests/ui/delegation/target-expr.stderr
@@ -1,16 +1,16 @@
 error[E0401]: can't use generic parameters from outer item
-  --> $DIR/target-expr.rs:20:17
+  --> $DIR/target-expr.rs:18:17
    |
 LL | fn bar<T: Default>(_: T) {
    |        - type parameter from outer item
 LL |     reuse Trait::static_method {
    |                               - help: try introducing a local generic parameter here: `T,`
-...
+LL |
 LL |         let _ = T::Default();
    |                 ^^^^^^^^^^ use of generic parameter from outer item
 
 error[E0434]: can't capture dynamic environment in a fn item
-  --> $DIR/target-expr.rs:29:17
+  --> $DIR/target-expr.rs:26:17
    |
 LL |         let x = y;
    |                 ^
@@ -18,7 +18,7 @@ LL |         let x = y;
    = help: use the `|| { ... }` closure form instead
 
 error[E0424]: expected value, found module `self`
-  --> $DIR/target-expr.rs:36:5
+  --> $DIR/target-expr.rs:33:5
    |
 LL | fn main() {
    |    ---- this function can't have a `self` parameter
@@ -27,58 +27,29 @@ LL |     self.0;
    |     ^^^^ `self` value is a keyword only available in methods with a `self` parameter
 
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/target-expr.rs:38:13
+  --> $DIR/target-expr.rs:35:13
    |
 LL |     let z = x;
    |             ^
    |
 help: the binding `x` is available in a different scope in the same function
-  --> $DIR/target-expr.rs:29:13
+  --> $DIR/target-expr.rs:26:13
    |
 LL |         let x = y;
    |             ^
 
-error: delegation with early bound generics is not supported yet
-  --> $DIR/target-expr.rs:16:18
-   |
-LL |     fn static_method(x: i32) -> i32 { x }
-   |     ------------------------------- callee defined here
-...
-LL |     reuse Trait::static_method {
-   |                  ^^^^^^^^^^^^^
-
-error: delegation to a trait method from a free function is not supported yet
-  --> $DIR/target-expr.rs:16:18
-   |
-LL |     fn static_method(x: i32) -> i32 { x }
-   |     ------------------------------- callee defined here
-...
-LL |     reuse Trait::static_method {
-   |                  ^^^^^^^^^^^^^
-
-error: delegation to a trait method from a free function is not supported yet
-  --> $DIR/target-expr.rs:27:25
-   |
-LL |     fn static_method(x: i32) -> i32 { x }
-   |     ------------------------------- callee defined here
-...
-LL |     reuse <S as Trait>::static_method {
-   |                         ^^^^^^^^^^^^^
-
 error[E0308]: mismatched types
   --> $DIR/target-expr.rs:16:32
    |
 LL |       reuse Trait::static_method {
    |  ________________________________^
 LL | |
-LL | |
-LL | |
 LL | |         let _ = T::Default();
 LL | |
 LL | |     }
    | |_____^ expected `i32`, found `()`
 
-error: aborting due to 8 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0308, E0401, E0424, E0425, E0434.
 For more information about an error, try `rustc --explain E0308`.