diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index e1e4e5fc56750..21077c312bdc8 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2873,6 +2873,7 @@ impl Item {
| ItemKind::ForeignMod(_)
| ItemKind::GlobalAsm(_)
| ItemKind::MacCall(_)
+ | ItemKind::Delegation(_)
| ItemKind::MacroDef(_) => None,
ItemKind::Static(_) => None,
ItemKind::Const(i) => Some(&i.generics),
@@ -3019,6 +3020,15 @@ pub struct Fn {
pub body: Option
>,
}
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Delegation {
+ /// Path resolution id.
+ pub id: NodeId,
+ pub qself: Option
>,
+ pub path: Path,
+ pub body: Option
>,
+}
+
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct StaticItem {
pub ty: P,
@@ -3104,6 +3114,11 @@ pub enum ItemKind {
/// A macro definition.
MacroDef(MacroDef),
+
+ /// A delegation item (`reuse`).
+ ///
+ /// E.g. `reuse ::name { target_expr_template }`.
+ Delegation(Box),
}
impl ItemKind {
@@ -3111,7 +3126,8 @@ impl ItemKind {
use ItemKind::*;
match self {
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
- | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..) => "a",
+ | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
+ | Delegation(..) => "a",
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
}
}
@@ -3135,6 +3151,7 @@ impl ItemKind {
ItemKind::MacCall(..) => "item macro invocation",
ItemKind::MacroDef(..) => "macro definition",
ItemKind::Impl { .. } => "implementation",
+ ItemKind::Delegation(..) => "delegated function",
}
}
@@ -3176,6 +3193,8 @@ pub enum AssocItemKind {
Type(Box),
/// A macro expanding to associated items.
MacCall(P),
+ /// An associated delegation item.
+ Delegation(Box),
}
impl AssocItemKind {
@@ -3184,7 +3203,7 @@ impl AssocItemKind {
Self::Const(box ConstItem { defaultness, .. })
| Self::Fn(box Fn { defaultness, .. })
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
- Self::MacCall(..) => Defaultness::Final,
+ Self::MacCall(..) | Self::Delegation(..) => Defaultness::Final,
}
}
}
@@ -3196,6 +3215,7 @@ impl From for ItemKind {
AssocItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
+ AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
}
}
}
@@ -3209,6 +3229,7 @@ impl TryFrom for AssocItemKind {
ItemKind::Fn(fn_kind) => AssocItemKind::Fn(fn_kind),
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
+ ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
_ => return Err(item_kind),
})
}
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 82f28143630d3..450555d0cb56d 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1117,6 +1117,14 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) {
}
ItemKind::MacCall(m) => vis.visit_mac_call(m),
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
+ ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
+ vis.visit_id(id);
+ vis.visit_qself(qself);
+ vis.visit_path(path);
+ if let Some(body) = body {
+ vis.visit_block(body);
+ }
+ }
}
}
@@ -1155,6 +1163,14 @@ pub fn noop_flat_map_assoc_item(
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
+ AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
+ visitor.visit_id(id);
+ visitor.visit_qself(qself);
+ visitor.visit_path(path);
+ if let Some(body) = body {
+ visitor.visit_block(body);
+ }
+ }
}
visitor.visit_span(span);
visit_lazy_tts(tokens, visitor);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 45261ca48fc25..3617df931e2a2 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -375,6 +375,15 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
}
ItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
ItemKind::MacroDef(ts) => visitor.visit_mac_def(ts, item.id),
+ ItemKind::Delegation(box Delegation { id: _, qself, path, body }) => {
+ if let Some(qself) = qself {
+ visitor.visit_ty(&qself.ty);
+ }
+ walk_path(visitor, path);
+ if let Some(body) = body {
+ visitor.visit_block(body);
+ }
+ }
}
walk_list!(visitor, visit_attribute, &item.attrs);
}
@@ -704,6 +713,15 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
AssocItemKind::MacCall(mac) => {
visitor.visit_mac_call(mac);
}
+ AssocItemKind::Delegation(box Delegation { id: _, qself, path, body }) => {
+ if let Some(qself) = qself {
+ visitor.visit_ty(&qself.ty);
+ }
+ walk_path(visitor, path);
+ if let Some(body) = body {
+ visitor.visit_block(body);
+ }
+ }
}
}
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
new file mode 100644
index 0000000000000..6ccf39b0cb167
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -0,0 +1,348 @@
+//! This module implements expansion of delegation items with early resolved paths.
+//! It includes a delegation to a free functions:
+//!
+//! ```ignore (illustrative)
+//! reuse module::name { target_expr_template }
+//! ```
+//!
+//! And delegation to a trait methods:
+//!
+//! ```ignore (illustrative)
+//! reuse ::name { target_expr_template }
+//! ```
+//!
+//! After expansion for both cases we get:
+//!
+//! ```ignore (illustrative)
+//! fn name(
+//! arg0: InferDelegation(sig_id, Input(0)),
+//! arg1: InferDelegation(sig_id, Input(1)),
+//! ...,
+//! argN: InferDelegation(sig_id, Input(N)),
+//! ) -> InferDelegation(sig_id, Output) {
+//! callee_path(target_expr_template(arg0), arg1, ..., argN)
+//! }
+//! ```
+//!
+//! Where `callee_path` is a path in delegation item e.g. `::name`.
+//! `sig_id` is a id of item from which the signature is inherited. It may be a delegation
+//! item id (`item_id`) in case of impl trait or path resolution id (`path_id`) otherwise.
+//!
+//! Since we do not have a proper way to obtain function type information by path resolution
+//! in AST, we mark each function parameter type as `InferDelegation` and inherit it in `AstConv`.
+//!
+//! Similarly generics, predicates and header are set to the "default" values.
+//! In case of discrepancy with callee function the `NotSupportedDelegation` error will
+//! also be emitted in `AstConv`.
+
+use crate::{ImplTraitPosition, ResolverAstLoweringExt};
+
+use super::{ImplTraitContext, LoweringContext, ParamMode};
+
+use ast::visit::Visitor;
+use hir::def::{DefKind, PartialRes, Res};
+use hir::{BodyId, HirId};
+use rustc_ast as ast;
+use rustc_ast::*;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_middle::span_bug;
+use rustc_middle::ty::ResolverAstLowering;
+use rustc_span::{symbol::Ident, Span};
+use rustc_target::spec::abi;
+use std::iter;
+
+pub(crate) struct DelegationResults<'hir> {
+ pub body_id: hir::BodyId,
+ pub sig: hir::FnSig<'hir>,
+ pub generics: &'hir hir::Generics<'hir>,
+}
+
+impl<'hir> LoweringContext<'_, 'hir> {
+ pub(crate) fn delegation_has_self(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool {
+ let sig_id = self.get_delegation_sig_id(item_id, path_id, span);
+ let Ok(sig_id) = sig_id else {
+ return false;
+ };
+ if let Some(local_sig_id) = sig_id.as_local() {
+ self.resolver.has_self.contains(&local_sig_id)
+ } else {
+ match self.tcx.def_kind(sig_id) {
+ DefKind::Fn => false,
+ DefKind::AssocFn => self.tcx.associated_item(sig_id).fn_has_self_parameter,
+ _ => span_bug!(span, "unexpected DefKind for delegation item"),
+ }
+ }
+ }
+
+ pub(crate) fn lower_delegation(
+ &mut self,
+ delegation: &Delegation,
+ item_id: NodeId,
+ ) -> DelegationResults<'hir> {
+ let span = delegation.path.segments.last().unwrap().ident.span;
+ let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span);
+ match sig_id {
+ Ok(sig_id) => {
+ let decl = self.lower_delegation_decl(sig_id, span);
+ let sig = self.lower_delegation_sig(span, decl);
+ let body_id = self.lower_delegation_body(sig.decl, delegation);
+
+ let generics = self.lower_delegation_generics(span);
+ DelegationResults { body_id, sig, generics }
+ }
+ Err(err) => self.generate_delegation_error(err, span),
+ }
+ }
+
+ fn get_delegation_sig_id(
+ &self,
+ item_id: NodeId,
+ path_id: NodeId,
+ span: Span,
+ ) -> Result {
+ let sig_id = if self.is_in_trait_impl { item_id } else { path_id };
+ let sig_id = self
+ .resolver
+ .get_partial_res(sig_id)
+ .map(|r| r.expect_full_res().opt_def_id())
+ .unwrap_or(None);
+
+ sig_id.ok_or_else(|| {
+ self.tcx
+ .dcx()
+ .span_delayed_bug(span, "LoweringContext: couldn't resolve delegation item")
+ })
+ }
+
+ fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
+ self.arena.alloc(hir::Generics {
+ params: &[],
+ predicates: &[],
+ has_where_clause_predicates: false,
+ where_clause_span: span,
+ span: span,
+ })
+ }
+
+ fn lower_delegation_decl(
+ &mut self,
+ sig_id: DefId,
+ param_span: Span,
+ ) -> &'hir hir::FnDecl<'hir> {
+ let args_count = if let Some(local_sig_id) = sig_id.as_local() {
+ // Map may be filled incorrectly due to recursive delegation.
+ // Error will be emmited later in astconv.
+ self.resolver.fn_parameter_counts.get(&local_sig_id).cloned().unwrap_or_default()
+ } else {
+ self.tcx.fn_arg_names(sig_id).len()
+ };
+ let inputs = self.arena.alloc_from_iter((0..args_count).into_iter().map(|arg| hir::Ty {
+ hir_id: self.next_id(),
+ kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
+ span: self.lower_span(param_span),
+ }));
+
+ let output = self.arena.alloc(hir::Ty {
+ hir_id: self.next_id(),
+ kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
+ span: self.lower_span(param_span),
+ });
+
+ self.arena.alloc(hir::FnDecl {
+ inputs,
+ output: hir::FnRetTy::Return(output),
+ c_variadic: false,
+ lifetime_elision_allowed: true,
+ implicit_self: hir::ImplicitSelfKind::None,
+ })
+ }
+
+ fn lower_delegation_sig(
+ &mut self,
+ span: Span,
+ decl: &'hir hir::FnDecl<'hir>,
+ ) -> hir::FnSig<'hir> {
+ hir::FnSig {
+ decl,
+ header: hir::FnHeader {
+ unsafety: hir::Unsafety::Normal,
+ constness: hir::Constness::NotConst,
+ asyncness: hir::IsAsync::NotAsync,
+ abi: abi::Abi::Rust,
+ },
+ span: self.lower_span(span),
+ }
+ }
+
+ fn generate_param(&mut self, ty: &'hir hir::Ty<'hir>) -> (hir::Param<'hir>, NodeId) {
+ let pat_node_id = self.next_node_id();
+ let pat_id = self.lower_node_id(pat_node_id);
+ let pat = self.arena.alloc(hir::Pat {
+ hir_id: pat_id,
+ kind: hir::PatKind::Binding(hir::BindingAnnotation::NONE, pat_id, Ident::empty(), None),
+ span: ty.span,
+ default_binding_modes: false,
+ });
+
+ (hir::Param { hir_id: self.next_id(), pat, ty_span: ty.span, span: ty.span }, pat_node_id)
+ }
+
+ fn generate_arg(&mut self, ty: &'hir hir::Ty<'hir>, param_id: HirId) -> hir::Expr<'hir> {
+ let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
+ ident: Ident::empty(),
+ hir_id: self.next_id(),
+ res: Res::Local(param_id),
+ args: None,
+ infer_args: false,
+ }));
+
+ let path =
+ self.arena.alloc(hir::Path { span: ty.span, res: Res::Local(param_id), segments });
+
+ hir::Expr {
+ hir_id: self.next_id(),
+ kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
+ span: ty.span,
+ }
+ }
+
+ fn lower_delegation_body(
+ &mut self,
+ decl: &'hir hir::FnDecl<'hir>,
+ delegation: &Delegation,
+ ) -> BodyId {
+ let path = self.lower_qpath(
+ delegation.id,
+ &delegation.qself,
+ &delegation.path,
+ ParamMode::Optional,
+ &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
+ );
+ let block = delegation.body.as_deref();
+
+ self.lower_body(|this| {
+ let mut parameters: Vec> = Vec::new();
+ let mut args: Vec> = Vec::new();
+
+ for (idx, param_ty) in decl.inputs.iter().enumerate() {
+ let (param, pat_node_id) = this.generate_param(param_ty);
+ parameters.push(param);
+
+ let arg = if let Some(block) = block
+ && idx == 0
+ {
+ let mut self_resolver = SelfResolver {
+ resolver: this.resolver,
+ path_id: delegation.id,
+ self_param_id: pat_node_id,
+ };
+ self_resolver.visit_block(block);
+ let block = this.lower_block(block, false);
+ hir::Expr {
+ hir_id: this.next_id(),
+ kind: hir::ExprKind::Block(block, None),
+ span: block.span,
+ }
+ } else {
+ let pat_hir_id = this.lower_node_id(pat_node_id);
+ this.generate_arg(param_ty, pat_hir_id)
+ };
+ args.push(arg);
+ }
+
+ let args = self.arena.alloc_from_iter(args);
+ let final_expr = this.generate_call(path, args);
+ (this.arena.alloc_from_iter(parameters), final_expr)
+ })
+ }
+
+ fn generate_call(
+ &mut self,
+ path: hir::QPath<'hir>,
+ args: &'hir [hir::Expr<'hir>],
+ ) -> hir::Expr<'hir> {
+ let callee = self.arena.alloc(hir::Expr {
+ hir_id: self.next_id(),
+ kind: hir::ExprKind::Path(path),
+ span: path.span(),
+ });
+
+ let expr = self.arena.alloc(hir::Expr {
+ hir_id: self.next_id(),
+ kind: hir::ExprKind::Call(callee, args),
+ span: path.span(),
+ });
+
+ let block = self.arena.alloc(hir::Block {
+ stmts: &[],
+ expr: Some(expr),
+ hir_id: self.next_id(),
+ rules: hir::BlockCheckMode::DefaultBlock,
+ span: path.span(),
+ targeted_by_break: false,
+ });
+
+ hir::Expr {
+ hir_id: self.next_id(),
+ kind: hir::ExprKind::Block(block, None),
+ span: path.span(),
+ }
+ }
+
+ fn generate_delegation_error(
+ &mut self,
+ err: ErrorGuaranteed,
+ span: Span,
+ ) -> DelegationResults<'hir> {
+ let generics = self.lower_delegation_generics(span);
+
+ let decl = self.arena.alloc(hir::FnDecl {
+ inputs: &[],
+ output: hir::FnRetTy::DefaultReturn(span),
+ c_variadic: false,
+ lifetime_elision_allowed: true,
+ implicit_self: hir::ImplicitSelfKind::None,
+ });
+
+ let sig = self.lower_delegation_sig(span, decl);
+ let body_id = self.lower_body(|this| {
+ let expr =
+ hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span };
+ (&[], expr)
+ });
+ DelegationResults { generics, body_id, sig }
+ }
+}
+
+struct SelfResolver<'a> {
+ resolver: &'a mut ResolverAstLowering,
+ path_id: NodeId,
+ self_param_id: NodeId,
+}
+
+impl<'a> SelfResolver<'a> {
+ fn try_replace_id(&mut self, id: NodeId) {
+ if let Some(res) = self.resolver.partial_res_map.get(&id)
+ && let Some(Res::Local(sig_id)) = res.full_res()
+ && sig_id == self.path_id
+ {
+ let new_res = PartialRes::new(Res::Local(self.self_param_id));
+ self.resolver.partial_res_map.insert(id, new_res);
+ }
+ }
+}
+
+impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a> {
+ fn visit_path(&mut self, path: &'ast Path, id: NodeId) {
+ self.try_replace_id(id);
+ visit::walk_path(self, path);
+ }
+
+ fn visit_path_segment(&mut self, seg: &'ast PathSegment) {
+ self.try_replace_id(seg.id);
+ visit::walk_path_segment(self, seg);
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index d8de447e5b4cd..a3ff02f5f6954 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -441,6 +441,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
hir::ItemKind::Macro(macro_def, macro_kind)
}
+ ItemKind::Delegation(box delegation) => {
+ let delegation_results = self.lower_delegation(delegation, id);
+ hir::ItemKind::Fn(
+ delegation_results.sig,
+ delegation_results.generics,
+ delegation_results.body_id,
+ )
+ }
ItemKind::MacCall(..) => {
panic!("`TyMac` should have been expanded by now")
}
@@ -805,6 +813,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
(generics, kind, ty.is_some())
}
+ AssocItemKind::Delegation(box delegation) => {
+ let delegation_results = self.lower_delegation(delegation, i.id);
+ let item_kind = hir::TraitItemKind::Fn(
+ delegation_results.sig,
+ hir::TraitFn::Provided(delegation_results.body_id),
+ );
+ (delegation_results.generics, item_kind, true)
+ }
AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
};
@@ -826,6 +842,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
+ AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
+ has_self: self.delegation_has_self(i.id, delegation.id, i.span),
+ },
AssocItemKind::MacCall(..) => unimplemented!(),
};
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
@@ -908,6 +927,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
},
)
}
+ AssocItemKind::Delegation(box delegation) => {
+ let delegation_results = self.lower_delegation(delegation, i.id);
+ (
+ delegation_results.generics,
+ hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
+ )
+ }
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
};
@@ -924,6 +950,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
+ let trait_item_def_id = self
+ .resolver
+ .get_partial_res(i.id)
+ .map(|r| r.expect_full_res().opt_def_id())
+ .unwrap_or(None);
+ self.is_in_trait_impl = trait_item_def_id.is_some();
+
hir::ImplItemRef {
id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
ident: self.lower_ident(i.ident),
@@ -934,12 +967,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
+ AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
+ has_self: self.delegation_has_self(i.id, delegation.id, i.span),
+ },
AssocItemKind::MacCall(..) => unimplemented!(),
},
- trait_item_def_id: self
- .resolver
- .get_partial_res(i.id)
- .map(|r| r.expect_full_res().def_id()),
+ trait_item_def_id,
}
}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index dc23b1dce7bf5..d2d42a15808ba 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -77,6 +77,7 @@ macro_rules! arena_vec {
mod asm;
mod block;
+mod delegation;
mod errors;
mod expr;
mod format;
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 737e81eb6ecc0..539b520f54f4e 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -556,6 +556,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(explicit_tail_calls, "`become` expression is experimental");
gate_all!(generic_const_items, "generic const items are experimental");
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
+ gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
if !visitor.features.never_patterns {
if let Some(spans) = spans.get(&sym::never_patterns) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 43561a1c0209c..584f01e16c2c3 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -376,6 +376,9 @@ impl<'a> State<'a> {
state.print_visibility(&item.vis)
});
}
+ ast::ItemKind::Delegation(box delegation) => {
+ self.print_delegation(delegation, &item.vis, &item.attrs)
+ }
}
self.ann.post(self, AnnNode::Item(item))
}
@@ -554,10 +557,38 @@ impl<'a> State<'a> {
self.word(";");
}
}
+ ast::AssocItemKind::Delegation(box delegation) => {
+ self.print_delegation(delegation, vis, &item.attrs)
+ }
}
self.ann.post(self, AnnNode::SubItem(id))
}
+ pub(crate) fn print_delegation(
+ &mut self,
+ delegation: &ast::Delegation,
+ vis: &ast::Visibility,
+ attrs: &[ast::Attribute],
+ ) {
+ if delegation.body.is_some() {
+ self.head("");
+ }
+ self.print_visibility(vis);
+ self.word_space("reuse");
+
+ if let Some(qself) = &delegation.qself {
+ self.print_qpath(&delegation.path, qself, false);
+ } else {
+ self.print_path(&delegation.path, false, 0);
+ }
+ if let Some(body) = &delegation.body {
+ self.nbsp();
+ self.print_block_with_attrs(body, attrs);
+ } else {
+ self.word(";");
+ }
+ }
+
fn print_fn_full(
&mut self,
sig: &ast::FnSig,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 58ac9668da5e9..6b347f7035a3b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2571,9 +2571,17 @@ pub enum OpaqueTyOrigin {
},
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)]
+pub enum InferDelegationKind {
+ Input(usize),
+ Output,
+}
+
/// The various kinds of types recognized by the compiler.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TyKind<'hir> {
+ /// Actual type should be inherited from `DefId` signature
+ InferDelegation(DefId, InferDelegationKind),
/// A variable length slice (i.e., `[T]`).
Slice(&'hir Ty<'hir>),
/// A fixed length array (i.e., `[T; n]`).
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index dd3633b6b4f74..adc090258093a 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -856,7 +856,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
visitor.visit_lifetime(lifetime);
}
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
- TyKind::Infer | TyKind::Err(_) => {}
+ TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
}
}
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 6a17668ad17f8..432c9c12cbfbc 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -263,6 +263,10 @@ 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
+ .label = callee defined here
+
hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 2886ec213201d..78740ac33ca09 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -29,10 +29,9 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability::AllowUnstable;
-use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{
- self, Const, GenericArgKind, GenericArgsRef, IsSuggestable, ParamEnv, Ty, TyCtxt,
- TypeVisitableExt,
+ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, IsSuggestable, ParamEnv, Ty,
+ TyCtxt, TypeVisitableExt,
};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
@@ -2322,6 +2321,114 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.ast_ty_to_ty_inner(ast_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.tcx().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 = self.tcx().fn_sig(sig_id).instantiate_identity();
+ if sig.output().has_opaque_types() {
+ try_emit("delegation to a function with opaque type");
+ }
+
+ let sig_generics = self.tcx().generics_of(sig_id);
+ let parent = self.tcx().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");
+ }
+
+ if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes {
+ try_emit("delegation to async functions");
+ }
+
+ if self.tcx().constness(sig_id) == hir::Constness::Const {
+ try_emit("delegation to const functions");
+ }
+
+ if sig.c_variadic() {
+ try_emit("delegation to variadic functions");
+ // variadic functions are also `unsafe` and `extern "C"`.
+ // Do not emit same error multiple times.
+ return error_occured;
+ }
+
+ if let hir::Unsafety::Unsafe = sig.unsafety() {
+ try_emit("delegation to unsafe functions");
+ }
+
+ if abi::Abi::Rust != sig.abi() {
+ try_emit("delegation to non Rust ABI functions");
+ }
+
+ error_occured
+ }
+
+ fn ty_from_delegation(
+ &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.tcx().dcx().span_delayed_bug(span, "not supported delegation case");
+ self.set_tainted_by_errors(e);
+ 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().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 substs = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
+ sig.instantiate(self.tcx(), substs)
+ } else {
+ sig.instantiate_identity()
+ };
+
+ // Bound vars are also inherited from `sig_id`. They will be
+ // rebinded later in `ty_of_fn`.
+ let sig = sig.skip_binder();
+
+ match idx {
+ hir::InferDelegationKind::Input(id) => sig.inputs()[id],
+ hir::InferDelegationKind::Output => sig.output(),
+ }
+ }
+
/// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait
/// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors.
#[instrument(level = "debug", skip(self), ret)]
@@ -2329,6 +2436,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let tcx = self.tcx();
let result_ty = match &ast_ty.kind {
+ hir::TyKind::InferDelegation(sig_id, idx) => {
+ self.ty_from_delegation(*sig_id, *idx, ast_ty.span)
+ }
hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.ast_ty_to_ty(ty)),
hir::TyKind::Ptr(mt) => {
Ty::new_ptr(tcx, ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
@@ -2520,7 +2630,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
hir_ty: Option<&hir::Ty<'_>>,
) -> ty::PolyFnSig<'tcx> {
let tcx = self.tcx();
- let bound_vars = tcx.late_bound_vars(hir_id);
+ let bound_vars = if let hir::FnRetTy::Return(ret_ty) = decl.output
+ && let hir::TyKind::InferDelegation(sig_id, _) = ret_ty.kind
+ {
+ tcx.fn_sig(sig_id).skip_binder().bound_vars()
+ } else {
+ tcx.late_bound_vars(hir_id)
+ };
debug!(?bound_vars);
// We proactively collect all the inferred type params to emit a single error per fn def.
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 4f22da4ba3b98..f14390b77c6e2 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1501,3 +1501,13 @@ pub enum RefOfMutStaticSugg {
var: String,
},
}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_not_supported_delegation)]
+pub struct NotSupportedDelegation<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub descr: &'a str,
+ #[label]
+ pub callee_span: Span,
+}
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 1eaec9970537d..d36e0892d19d9 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -320,7 +320,7 @@ impl<'a> State<'a> {
self.word("/*ERROR*/");
self.pclose();
}
- hir::TyKind::Infer => {
+ hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
self.word("_");
}
}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 9e8d7c2ef3ecb..ad9296a4cc88a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -42,7 +42,7 @@ use rustc_data_structures::unord::UnordMap;
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet};
use rustc_index::IndexVec;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
@@ -202,6 +202,10 @@ pub struct ResolverAstLowering {
/// Lints that were emitted by the resolver and early lints.
pub lint_buffer: Steal,
+
+ /// Information about functions signatures for delegation items expansion
+ pub has_self: LocalDefIdSet,
+ pub fn_parameter_counts: LocalDefIdMap,
}
#[derive(Clone, Copy, Debug)]
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index bcff820da7960..3bd8ae0258628 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -252,6 +252,8 @@ impl<'a> Parser<'a> {
{
// IMPL ITEM
self.parse_item_impl(attrs, def_())?
+ } else if self.is_reuse_path_item() {
+ self.parse_item_delegation()?
} else if self.check_keyword(kw::Mod)
|| self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod])
{
@@ -349,11 +351,18 @@ impl<'a> Parser<'a> {
/// When parsing a statement, would the start of a path be an item?
pub(super) fn is_path_start_item(&mut self) -> bool {
self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
+ || self.is_reuse_path_item()
|| self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
|| self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
|| matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
}
+ fn is_reuse_path_item(&mut self) -> bool {
+ // no: `reuse ::path` for compatibility reasons with macro invocations
+ self.token.is_keyword(kw::Reuse)
+ && self.look_ahead(1, |t| t.is_path_start() && t.kind != token::ModSep)
+ }
+
/// Are we sure this could not possibly be a macro invocation?
fn isnt_macro_invocation(&mut self) -> bool {
self.check_ident() && self.look_ahead(1, |t| *t != token::Not && *t != token::ModSep)
@@ -655,6 +664,33 @@ impl<'a> Parser<'a> {
Ok((Ident::empty(), item_kind))
}
+ fn parse_item_delegation(&mut self) -> PResult<'a, ItemInfo> {
+ let span = self.token.span;
+ self.expect_keyword(kw::Reuse)?;
+
+ let (qself, path) = if self.eat_lt() {
+ let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+ (Some(qself), path)
+ } else {
+ (None, self.parse_path(PathStyle::Expr)?)
+ };
+
+ let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
+ Some(self.parse_block()?)
+ } else {
+ self.expect(&token::Semi)?;
+ None
+ };
+ let span = span.to(self.prev_token.span);
+ self.sess.gated_spans.gate(sym::fn_delegation, span);
+
+ let ident = path.segments.last().map(|seg| seg.ident).unwrap_or(Ident::empty());
+ Ok((
+ ident,
+ ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, body })),
+ ))
+ }
+
fn parse_item_list(
&mut self,
attrs: &mut AttrVec,
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index c2392620cb285..ff29fc5929c76 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -341,6 +341,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
record_variants!(
(self, t, t.kind, Id::Node(t.hir_id), hir, Ty, TyKind),
[
+ InferDelegation,
Slice,
Array,
Ptr,
@@ -521,7 +522,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
TraitAlias,
Impl,
MacCall,
- MacroDef
+ MacroDef,
+ Delegation
]
);
ast_visit::walk_item(self, i)
@@ -645,7 +647,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
record_variants!(
(self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind),
- [Const, Fn, Type, MacCall]
+ [Const, Fn, Type, MacCall, Delegation]
);
ast_visit::walk_assoc_item(self, i, ctxt);
}
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 647f4d0e08419..6aeaa8945fb59 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -271,7 +271,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
ast::ItemKind::Use(_) => Target::Use,
ast::ItemKind::Static(_) => Target::Static,
ast::ItemKind::Const(_) => Target::Const,
- ast::ItemKind::Fn(_) => Target::Fn,
+ ast::ItemKind::Fn(_) | ast::ItemKind::Delegation(..) => Target::Fn,
ast::ItemKind::Mod(_, _) => Target::Mod,
ast::ItemKind::ForeignMod(_) => Target::ForeignFn,
ast::ItemKind::GlobalAsm(_) => Target::GlobalAsm,
@@ -315,24 +315,29 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
fn visit_assoc_item(&mut self, i: &'ast ast::AssocItem, ctxt: visit::AssocCtxt) {
let (target, generics) = match &i.kind {
- ast::AssocItemKind::Fn(fun) => (
- match &self.parent_item.unwrap().kind {
- ast::ItemKind::Impl(i) => {
- if i.of_trait.is_some() {
- Target::Method(MethodKind::Trait { body: fun.body.is_some() })
- } else {
- Target::Method(MethodKind::Inherent)
+ ast::AssocItemKind::Fn(..) | ast::AssocItemKind::Delegation(..) => {
+ let (body, generics) = if let ast::AssocItemKind::Fn(fun) = &i.kind {
+ (fun.body.is_some(), Some(&fun.generics))
+ } else {
+ (true, None)
+ };
+ (
+ match &self.parent_item.unwrap().kind {
+ ast::ItemKind::Impl(i) => {
+ if i.of_trait.is_some() {
+ Target::Method(MethodKind::Trait { body })
+ } else {
+ Target::Method(MethodKind::Inherent)
+ }
}
- }
- ast::ItemKind::Trait(_) => {
- Target::Method(MethodKind::Trait { body: fun.body.is_some() })
- }
- _ => unreachable!(),
- },
- &fun.generics,
- ),
- ast::AssocItemKind::Const(ct) => (Target::AssocConst, &ct.generics),
- ast::AssocItemKind::Type(ty) => (Target::AssocTy, &ty.generics),
+ ast::ItemKind::Trait(_) => Target::Method(MethodKind::Trait { body }),
+ _ => unreachable!(),
+ },
+ generics,
+ )
+ }
+ ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)),
+ ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)),
ast::AssocItemKind::MacCall(_) => unreachable!("macros should have been expanded"),
};
@@ -341,7 +346,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
self.resolver.node_id_to_def_id[&i.id],
&i.attrs,
i.span,
- Some(generics),
+ generics,
);
visit::walk_assoc_item(self, i, ctxt);
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 9ccfde5e3c621..a4e2f9e3ff8cd 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -16,7 +16,7 @@ use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
-use rustc_ast::{Block, Fn, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
+use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
use rustc_attr as attr;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_code_err, Applicability};
@@ -686,10 +686,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
}
// These items live in the value namespace.
- ItemKind::Static(..) => {
- self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
- }
- ItemKind::Const(..) => {
+ ItemKind::Const(..) | ItemKind::Delegation(..) | ItemKind::Static(..) => {
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
}
ItemKind::Fn(..) => {
@@ -701,11 +698,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
}
// These items live in the type namespace.
- ItemKind::TyAlias(..) => {
+ ItemKind::TyAlias(..) | ItemKind::TraitAlias(..) => {
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
- ItemKind::Enum(_, _) => {
+ ItemKind::Enum(_, _) | ItemKind::Trait(..) => {
let module = self.r.new_module(
Some(parent),
ModuleKind::Def(def_kind, def_id, ident.name),
@@ -717,10 +714,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.parent_scope.module = module;
}
- ItemKind::TraitAlias(..) => {
- self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
- }
-
// These items live in both the type and value namespaces.
ItemKind::Struct(ref vdata, _) => {
// Define a name in the type namespace.
@@ -778,19 +771,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.insert_field_visibilities_local(def_id, vdata);
}
- ItemKind::Trait(..) => {
- // Add all the items within to a new module.
- let module = self.r.new_module(
- Some(parent),
- ModuleKind::Def(def_kind, def_id, ident.name),
- expansion.to_expn_id(),
- item.span,
- parent.no_implicit_prelude,
- );
- self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
- self.parent_scope.module = module;
- }
-
// These items do not add names to modules.
ItemKind::Impl(box Impl { of_trait: Some(..), .. }) => {
self.r.trait_impl_items.insert(local_def_id);
@@ -1358,13 +1338,9 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
if ctxt == AssocCtxt::Trait {
let ns = match item.kind {
- AssocItemKind::Const(..) => ValueNS,
- AssocItemKind::Fn(box Fn { ref sig, .. }) => {
- if sig.decl.has_self() {
- self.r.has_self.insert(local_def_id);
- }
- ValueNS
- }
+ AssocItemKind::Const(..)
+ | AssocItemKind::Delegation(..)
+ | AssocItemKind::Fn(..) => ValueNS,
AssocItemKind::Type(..) => TypeNS,
AssocItemKind::MacCall(_) => bug!(), // handled above
};
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 02553d5007155..b77102c085c59 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -111,7 +111,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
ItemKind::TyAlias(..) => DefKind::TyAlias,
ItemKind::Static(s) => DefKind::Static(s.mutability),
ItemKind::Const(..) => DefKind::Const,
- ItemKind::Fn(..) => DefKind::Fn,
+ ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn,
ItemKind::MacroDef(..) => {
let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition());
let macro_kind = macro_data.ext.macro_kind();
@@ -259,7 +259,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
let def_kind = match &i.kind {
- AssocItemKind::Fn(..) => DefKind::AssocFn,
+ AssocItemKind::Fn(..) | AssocItemKind::Delegation(..) => DefKind::AssocFn,
AssocItemKind::Const(..) => DefKind::AssocConst,
AssocItemKind::Type(..) => DefKind::AssocTy,
AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 50352169221d7..3443bbe6e1158 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -277,7 +277,8 @@ impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 't
| ast::ItemKind::TraitAlias(..)
| ast::ItemKind::MacroDef(..)
| ast::ItemKind::ForeignMod(..)
- | ast::ItemKind::Fn(..) => return,
+ | ast::ItemKind::Fn(..)
+ | ast::ItemKind::Delegation(..) => return,
}
}
}
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 4a3c8dfe3d729..b9e603a499266 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -394,13 +394,18 @@ pub(crate) enum PathSource<'a> {
TupleStruct(Span, &'a [Span]),
// `m::A::B` in `::B::C`.
TraitItem(Namespace),
+ // Paths in delegation item
+ Delegation,
}
impl<'a> PathSource<'a> {
fn namespace(self) -> Namespace {
match self {
PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS,
- PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) => ValueNS,
+ PathSource::Expr(..)
+ | PathSource::Pat
+ | PathSource::TupleStruct(..)
+ | PathSource::Delegation => ValueNS,
PathSource::TraitItem(ns) => ns,
}
}
@@ -412,7 +417,7 @@ impl<'a> PathSource<'a> {
| PathSource::Pat
| PathSource::Struct
| PathSource::TupleStruct(..) => true,
- PathSource::Trait(_) | PathSource::TraitItem(..) => false,
+ PathSource::Trait(_) | PathSource::TraitItem(..) | PathSource::Delegation => false,
}
}
@@ -454,6 +459,7 @@ impl<'a> PathSource<'a> {
},
_ => "value",
},
+ PathSource::Delegation => "function",
}
}
@@ -521,6 +527,7 @@ impl<'a> PathSource<'a> {
Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
_ => false,
},
+ PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)),
}
}
@@ -533,8 +540,8 @@ impl<'a> PathSource<'a> {
(PathSource::Type, false) => error_code!(E0412),
(PathSource::Struct, true) => error_code!(E0574),
(PathSource::Struct, false) => error_code!(E0422),
- (PathSource::Expr(..), true) => error_code!(E0423),
- (PathSource::Expr(..), false) => error_code!(E0425),
+ (PathSource::Expr(..), true) | (PathSource::Delegation, true) => error_code!(E0423),
+ (PathSource::Expr(..), false) | (PathSource::Delegation, false) => error_code!(E0425),
(PathSource::Pat | PathSource::TupleStruct(..), true) => error_code!(E0532),
(PathSource::Pat | PathSource::TupleStruct(..), false) => error_code!(E0531),
(PathSource::TraitItem(..), true) => error_code!(E0575),
@@ -1805,7 +1812,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
PathSource::Expr(..)
| PathSource::Pat
| PathSource::Struct
- | PathSource::TupleStruct(..) => true,
+ | PathSource::TupleStruct(..)
+ | PathSource::Delegation => true,
};
if inferred {
// Do not create a parameter for patterns and expressions: type checking can infer
@@ -2514,6 +2522,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
visit::walk_item(self, item);
}
+ ItemKind::Delegation(ref delegation) => {
+ self.resolve_delegation(delegation);
+ }
+
ItemKind::ExternCrate(..) => {}
ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"),
@@ -2790,6 +2802,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
}
+ AssocItemKind::Delegation(delegation) => {
+ self.resolve_delegation(delegation);
+ }
AssocItemKind::Type(box TyAlias { generics, .. }) => self
.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
@@ -3036,6 +3051,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
},
);
}
+ AssocItemKind::Delegation(box delegation) => {
+ debug!("resolve_implementation AssocItemKind::Delegation");
+ self.check_trait_item(
+ item.id,
+ item.ident,
+ &item.kind,
+ ValueNS,
+ item.span,
+ seen_trait_items,
+ |i, s, c| MethodNotMemberOfTrait(i, s, c),
+ );
+ self.resolve_delegation(delegation);
+ }
AssocItemKind::MacCall(_) => {
panic!("unexpanded macro in resolve!")
}
@@ -3123,7 +3151,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
match (def_kind, kind) {
(DefKind::AssocTy, AssocItemKind::Type(..))
| (DefKind::AssocFn, AssocItemKind::Fn(..))
- | (DefKind::AssocConst, AssocItemKind::Const(..)) => {
+ | (DefKind::AssocConst, AssocItemKind::Const(..))
+ | (DefKind::AssocFn, AssocItemKind::Delegation(..)) => {
self.r.record_partial_res(id, PartialRes::new(res));
return;
}
@@ -3136,6 +3165,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
AssocItemKind::Const(..) => (rustc_errors::error_code!(E0323), "const"),
AssocItemKind::Fn(..) => (rustc_errors::error_code!(E0324), "method"),
AssocItemKind::Type(..) => (rustc_errors::error_code!(E0325), "type"),
+ AssocItemKind::Delegation(..) => (rustc_errors::error_code!(E0324), "method"),
AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
};
let trait_path = path_names_to_string(path);
@@ -3159,6 +3189,32 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
})
}
+ fn resolve_delegation(&mut self, delegation: &'ast Delegation) {
+ self.smart_resolve_path(
+ delegation.id,
+ &delegation.qself,
+ &delegation.path,
+ PathSource::Delegation,
+ );
+ if let Some(qself) = &delegation.qself {
+ self.visit_ty(&qself.ty);
+ }
+ self.visit_path(&delegation.path, delegation.id);
+ if let Some(body) = &delegation.body {
+ // `PatBoundCtx` is not necessary in this context
+ let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
+
+ let span = delegation.path.segments.last().unwrap().ident.span;
+ self.fresh_binding(
+ Ident::new(kw::SelfLower, span),
+ delegation.id,
+ PatternSource::FnParam,
+ &mut bindings,
+ );
+ self.visit_block(body);
+ }
+ }
+
fn resolve_params(&mut self, params: &'ast [Param]) {
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
@@ -4551,13 +4607,24 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
}
-struct LifetimeCountVisitor<'a, 'b, 'tcx> {
+/// Walks the whole crate in DFS order, visiting each item, counting the declared number of
+/// lifetime generic parameters and function parameters.
+struct ItemInfoCollector<'a, 'b, 'tcx> {
r: &'b mut Resolver<'a, 'tcx>,
}
-/// Walks the whole crate in DFS order, visiting each item, counting the declared number of
-/// lifetime generic parameters.
-impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
+impl ItemInfoCollector<'_, '_, '_> {
+ fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId) {
+ let def_id = self.r.local_def_id(id);
+ self.r.fn_parameter_counts.insert(def_id, sig.decl.inputs.len());
+
+ if sig.decl.has_self() {
+ self.r.has_self.insert(def_id);
+ }
+ }
+}
+
+impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
fn visit_item(&mut self, item: &'ast Item) {
match &item.kind {
ItemKind::TyAlias(box TyAlias { ref generics, .. })
@@ -4569,6 +4636,10 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
| ItemKind::Impl(box Impl { ref generics, .. })
| ItemKind::Trait(box Trait { ref generics, .. })
| ItemKind::TraitAlias(ref generics, _) => {
+ if let ItemKind::Fn(box Fn { ref sig, .. }) = &item.kind {
+ self.collect_fn_info(sig, item.id);
+ }
+
let def_id = self.r.local_def_id(item.id);
let count = generics
.params
@@ -4586,14 +4657,27 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
| ItemKind::MacroDef(..)
| ItemKind::GlobalAsm(..)
| ItemKind::MacCall(..) => {}
+ ItemKind::Delegation(..) => {
+ // Delegated functions have lifetimes, their count is not necessarily zero.
+ // But skipping the delegation items here doesn't mean that the count will be considered zero,
+ // it means there will be a panic when retrieving the count,
+ // but for delegation items we are never actually retrieving that count in practice.
+ }
}
visit::walk_item(self, item)
}
+
+ fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) {
+ if let AssocItemKind::Fn(box Fn { ref sig, .. }) = &item.kind {
+ self.collect_fn_info(sig, item.id);
+ }
+ visit::walk_assoc_item(self, item, ctxt);
+ }
}
impl<'a, 'tcx> Resolver<'a, 'tcx> {
pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
- visit::walk_crate(&mut LifetimeCountVisitor { r: self }, krate);
+ visit::walk_crate(&mut ItemInfoCollector { r: self }, krate);
let mut late_resolution_visitor = LateResolutionVisitor::new(self);
late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID));
visit::walk_crate(&mut late_resolution_visitor, krate);
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 2f476ae6cbcc1..58ff4d8c79349 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -656,7 +656,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let typo_sugg = self
.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
.to_opt_suggestion();
- if path.len() == 1 && self.self_type_is_available() {
+ if path.len() == 1
+ && !matches!(source, PathSource::Delegation)
+ && self.self_type_is_available()
+ {
if let Some(candidate) =
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
{
@@ -1899,6 +1902,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
(AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
(AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,
(AssocItemKind::Type(..), Res::Def(DefKind::AssocTy, _)) => true,
+ (AssocItemKind::Delegation(_), Res::Def(DefKind::AssocFn, _)) => true,
_ => false,
})
.map(|(key, _)| key.ident.name)
@@ -1960,6 +1964,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called },
ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType,
+ ast::AssocItemKind::Delegation(..)
+ if self.r.has_self.contains(&self.r.local_def_id(assoc_item.id)) =>
+ {
+ AssocSuggestion::MethodWithSelf { called }
+ }
+ ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
ast::AssocItemKind::MacCall(_) => continue,
});
}
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index a14f3d494fb4d..0adea65ee58ea 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1101,6 +1101,8 @@ pub struct Resolver<'a, 'tcx> {
legacy_const_generic_args: FxHashMap>>,
/// Amount of lifetime parameters for each item in the crate.
item_generics_num_lifetimes: FxHashMap,
+ /// Amount of parameters for each function in the crate.
+ fn_parameter_counts: LocalDefIdMap,
main_def: Option,
trait_impls: FxIndexMap>,
@@ -1439,6 +1441,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
doc_link_resolutions: Default::default(),
doc_link_traits_in_scope: Default::default(),
all_macro_rules: Default::default(),
+ fn_parameter_counts: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1542,6 +1545,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
trait_map: self.trait_map,
lifetime_elision_allowed: self.lifetime_elision_allowed,
lint_buffer: Steal::new(self.lint_buffer),
+ has_self: self.has_self,
+ fn_parameter_counts: self.fn_parameter_counts,
};
ResolverOutputs { global_ctxt, ast_lowering }
}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8ed1255c010f1..72b62a795fc50 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -102,6 +102,7 @@ symbols! {
Gen: "gen",
MacroRules: "macro_rules",
Raw: "raw",
+ Reuse: "reuse",
Union: "union",
Yeet: "yeet",
}
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9c0a8634990b3..124a2d9cba957 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1870,7 +1870,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
}
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
- TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) => Infer,
+ TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index aaef163ad554b..8ff54dfcfa0dc 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -830,6 +830,7 @@ impl TyCoercionStability {
| TyKind::Infer
| TyKind::Typeof(..)
| TyKind::TraitObject(..)
+ | TyKind::InferDelegation(..)
| TyKind::Err(_) => Self::Reborrow,
};
}
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 07b72e3f570b7..482eaed77d1d3 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1108,7 +1108,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
TyKind::Typeof(anon_const) => {
self.hash_body(anon_const.body);
},
- TyKind::Err(_) | TyKind::Infer | TyKind::Never => {},
+ TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) => {},
}
}
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 6fb69d6b88393..b57be8c10549e 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -728,7 +728,9 @@ impl<'a> FmtVisitor<'a> {
(Const(..), Const(..)) | (MacCall(..), MacCall(..)) => {
a.ident.as_str().cmp(b.ident.as_str())
}
- (Fn(..), Fn(..)) => a.span.lo().cmp(&b.span.lo()),
+ (Fn(..), Fn(..)) | (Delegation(..), Delegation(..)) => {
+ a.span.lo().cmp(&b.span.lo())
+ }
(Type(ty), _) if is_type(&ty.ty) => Ordering::Less,
(_, Type(ty)) if is_type(&ty.ty) => Ordering::Greater,
(Type(..), _) => Ordering::Less,
@@ -737,6 +739,8 @@ impl<'a> FmtVisitor<'a> {
(_, Const(..)) => Ordering::Greater,
(MacCall(..), _) => Ordering::Less,
(_, MacCall(..)) => Ordering::Greater,
+ (Delegation(..), _) => Ordering::Less,
+ (_, Delegation(..)) => Ordering::Greater,
});
let mut prev_kind = None;
for (buf, item) in buffer {
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index f4d84d1381fc0..bc5accefd92b8 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -592,6 +592,11 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
);
self.push_rewrite(item.span, rewrite);
}
+ ast::ItemKind::Delegation(..) => {
+ // TODO: rewrite delegation items once syntax is established.
+ // For now, leave the contents of the Span unformatted.
+ self.push_rewrite(item.span, None)
+ }
};
}
self.skip_context = skip_context_saved;
diff --git a/tests/pretty/delegation.rs b/tests/pretty/delegation.rs
new file mode 100644
index 0000000000000..6a46437f7d638
--- /dev/null
+++ b/tests/pretty/delegation.rs
@@ -0,0 +1,25 @@
+#![feature(fn_delegation)]
+//~^ WARN the feature `fn_delegation` is incomplete
+
+// pp-exact
+
+trait Trait {
+ fn bar(&self, x: i32) -> i32 { x }
+}
+
+struct F;
+impl Trait for F {}
+
+struct S(F);
+impl Trait for S {
+ reuse Trait::bar { &self.0 }
+}
+
+mod to_reuse {
+ pub fn foo() {}
+}
+
+#[inline]
+pub reuse to_reuse::foo;
+
+fn main() {}
diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs
new file mode 100644
index 0000000000000..df456f94507be
--- /dev/null
+++ b/tests/ui/delegation/bad-resolve.rs
@@ -0,0 +1,47 @@
+#![feature(fn_delegation)]
+//~^ WARN the feature `fn_delegation` is incomplete
+
+trait Trait {
+ const C: u32 = 0;
+ type Type;
+ fn bar() {}
+ fn foo(&self, x: i32) -> i32 { x }
+}
+
+struct F;
+impl Trait for F {
+ type Type = i32;
+}
+
+impl F {
+ fn foo(&self, x: i32) -> i32 { x }
+}
+
+struct S(F);
+
+impl Trait for S {
+//~^ ERROR not all trait items implemented, missing: `Type`
+ reuse ::C;
+ //~^ ERROR item `C` is an associated method, which doesn't match its trait `Trait`
+ //~| ERROR expected function, found associated constant `Trait::C`
+ reuse ::Type;
+ //~^ ERROR item `Type` is an associated method, which doesn't match its trait `Trait`
+ //~| ERROR expected method or associated constant, found associated type `Trait::Type`
+ reuse ::baz;
+ //~^ ERROR method `baz` is not a member of trait `Trait`
+ //~| ERROR cannot find method or associated constant `baz` in trait `Trait`
+ reuse ::bar;
+
+ reuse foo { &self.0 }
+ //~^ ERROR cannot find function `foo` in this scope
+ reuse F::foo { &self.0 }
+ //~^ ERROR cannot find function `foo` in `F`
+ //~| ERROR duplicate definitions with name `foo`
+}
+
+impl S {
+ reuse F::foo { &self.0 }
+ //~^ ERROR cannot find function `foo` in `F`
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr
new file mode 100644
index 0000000000000..d520663731002
--- /dev/null
+++ b/tests/ui/delegation/bad-resolve.stderr
@@ -0,0 +1,102 @@
+error[E0324]: item `C` is an associated method, which doesn't match its trait `Trait`
+ --> $DIR/bad-resolve.rs:24:5
+ |
+LL | const C: u32 = 0;
+ | ----------------- item in trait
+...
+LL | reuse ::C;
+ | ^^^^^^^^^^^^^^^^^^^^^^ does not match trait
+
+error[E0324]: item `Type` is an associated method, which doesn't match its trait `Trait`
+ --> $DIR/bad-resolve.rs:27:5
+ |
+LL | type Type;
+ | ---------- item in trait
+...
+LL | reuse ::Type;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait
+
+error[E0407]: method `baz` is not a member of trait `Trait`
+ --> $DIR/bad-resolve.rs:30:5
+ |
+LL | reuse ::baz;
+ | ^^^^^^^^^^^^^^^^^^^^---^
+ | | |
+ | | help: there is an associated function with a similar name: `bar`
+ | not a member of trait `Trait`
+
+error[E0201]: duplicate definitions with name `foo`:
+ --> $DIR/bad-resolve.rs:37:5
+ |
+LL | fn foo(&self, x: i32) -> i32 { x }
+ | ---------------------------------- item in trait
+...
+LL | reuse foo { &self.0 }
+ | --------------------- previous definition here
+LL |
+LL | reuse F::foo { &self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
+
+error[E0423]: expected function, found associated constant `Trait::C`
+ --> $DIR/bad-resolve.rs:24:11
+ |
+LL | reuse ::C;
+ | ^^^^^^^^^^^^^^^ not a function
+
+error[E0575]: expected method or associated constant, found associated type `Trait::Type`
+ --> $DIR/bad-resolve.rs:27:11
+ |
+LL | reuse ::Type;
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: can't use a type alias as a constructor
+
+error[E0576]: cannot find method or associated constant `baz` in trait `Trait`
+ --> $DIR/bad-resolve.rs:30:25
+ |
+LL | fn bar() {}
+ | -------- similarly named associated function `bar` defined here
+...
+LL | reuse ::baz;
+ | ^^^ help: an associated function with a similar name exists: `bar`
+
+error[E0425]: cannot find function `foo` in this scope
+ --> $DIR/bad-resolve.rs:35:11
+ |
+LL | reuse foo { &self.0 }
+ | ^^^ not found in this scope
+
+error[E0425]: cannot find function `foo` in `F`
+ --> $DIR/bad-resolve.rs:37:14
+ |
+LL | reuse F::foo { &self.0 }
+ | ^^^ not found in `F`
+
+error[E0425]: cannot find function `foo` in `F`
+ --> $DIR/bad-resolve.rs:43:14
+ |
+LL | reuse F::foo { &self.0 }
+ | ^^^ not found in `F`
+
+warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/bad-resolve.rs:1:12
+ |
+LL | #![feature(fn_delegation)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #118212 for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+error[E0046]: not all trait items implemented, missing: `Type`
+ --> $DIR/bad-resolve.rs:22:1
+ |
+LL | type Type;
+ | --------- `Type` from trait
+...
+LL | impl Trait for S {
+ | ^^^^^^^^^^^^^^^^ missing `Type` in implementation
+
+error: aborting due to 11 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0046, E0201, E0324, E0407, E0423, E0425, E0575, E0576.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/delegation/explicit-paths-in-traits-pass.rs b/tests/ui/delegation/explicit-paths-in-traits-pass.rs
new file mode 100644
index 0000000000000..5c41c2ff49c8d
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths-in-traits-pass.rs
@@ -0,0 +1,27 @@
+// run-pass
+
+#![feature(fn_delegation)]
+//~^ WARN the feature `fn_delegation` is incomplete
+
+trait ToReuse {
+ fn foo(&self, x: i32) -> i32 { x }
+ fn foo1(x: i32) -> i32 { x }
+}
+
+fn foo2() -> i32 { 42 }
+
+trait Trait: ToReuse {
+ reuse ToReuse::foo;
+ reuse ::foo1;
+ reuse foo2;
+}
+
+struct S;
+impl ToReuse for S {}
+impl Trait for S {}
+
+fn main() {
+ assert_eq!(::foo(&S, 1), 1);
+ assert_eq!(::foo1(1), 1);
+ assert_eq!(::foo2(), 42);
+}
diff --git a/tests/ui/delegation/explicit-paths-in-traits-pass.stderr b/tests/ui/delegation/explicit-paths-in-traits-pass.stderr
new file mode 100644
index 0000000000000..8a320b44e63db
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths-in-traits-pass.stderr
@@ -0,0 +1,11 @@
+warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/explicit-paths-in-traits-pass.rs:3:12
+ |
+LL | #![feature(fn_delegation)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #118212 for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/delegation/explicit-paths-pass.rs b/tests/ui/delegation/explicit-paths-pass.rs
new file mode 100644
index 0000000000000..331e06d9a8879
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths-pass.rs
@@ -0,0 +1,64 @@
+// run-pass
+
+#![feature(fn_delegation)]
+//~^ WARN the feature `fn_delegation` is incomplete
+
+trait Trait {
+ fn bar(&self, x: i32) -> i32 { x }
+ fn description(&self) -> &str {
+ "hello world!"
+ }
+ fn static_method(x: i32) -> i32 { x }
+ fn static_method2(x: i32, y: i32) -> i32 { x + y }
+ fn baz<'a>(&self, x: &'a i32) -> &'a i32 { x }
+}
+
+struct F;
+impl Trait for F {}
+
+mod to_reuse {
+ pub fn foo(x: i32) -> i32 { x + 1 }
+ pub fn zero_args() -> i32 { 15 }
+}
+
+reuse to_reuse::zero_args { self }
+
+struct S(F);
+impl Trait for S {
+ reuse Trait::bar { &self.0 }
+ reuse Trait::description { &self.0 }
+ reuse ::static_method;
+ reuse ::static_method2 { S::static_method(self) }
+ reuse Trait::baz { &self.0 }
+}
+
+impl S {
+ reuse Trait::baz { &self.0 }
+ reuse ::static_method { to_reuse::foo(self) }
+}
+
+impl std::fmt::Display for S {
+ reuse ::fmt { self.description() }
+}
+
+fn main() {
+ let s = S(F);
+ assert_eq!(42, s.bar(42));
+ assert_eq!("hello world!", format!("{s}"));
+ assert_eq!(43, S::static_method(42));
+ assert_eq!(42, ::static_method(42));
+ assert_eq!(21, S::static_method2(10, 10));
+
+ reuse ::static_method;
+ reuse ::static_method2 { static_method(self) }
+ #[inline]
+ reuse to_reuse::foo;
+ assert_eq!(42, static_method(42));
+ assert_eq!(21, static_method2(10, 10));
+ assert_eq!(43, foo(42));
+ assert_eq!(15, zero_args());
+
+ let x: i32 = 15;
+ assert_eq!(&x, ::baz(&s, &x));
+ assert_eq!(&x, S::baz(&s, &x));
+}
diff --git a/tests/ui/delegation/explicit-paths-pass.stderr b/tests/ui/delegation/explicit-paths-pass.stderr
new file mode 100644
index 0000000000000..6d25fb4a5a57d
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths-pass.stderr
@@ -0,0 +1,11 @@
+warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/explicit-paths-pass.rs:3:12
+ |
+LL | #![feature(fn_delegation)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #118212 for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/delegation/explicit-paths-signature-pass.rs b/tests/ui/delegation/explicit-paths-signature-pass.rs
new file mode 100644
index 0000000000000..826107130eb0e
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths-signature-pass.rs
@@ -0,0 +1,39 @@
+// run-pass
+
+#![feature(fn_delegation)]
+//~^ WARN the feature `fn_delegation` is incomplete
+
+mod to_reuse {
+ use crate::S;
+
+ pub fn foo<'a>(#[cfg(FALSE)] a: u8, _b: &'a S) -> u32 {
+ 1
+ }
+}
+
+reuse to_reuse::foo;
+
+trait Trait {
+ fn foo(&self) -> u32 { 0 }
+ fn bar(self: Box) -> u32 { 2 }
+ fn baz(a: (i32, i32)) -> i32 { a.0 + a.1 }
+}
+
+struct F;
+impl Trait for F {}
+
+struct S(F);
+
+impl Trait for S {
+ reuse to_reuse::foo { self }
+ reuse Trait::bar { Box::new(self.0) }
+ reuse ::baz;
+}
+
+fn main() {
+ let s = S(F);
+ assert_eq!(1, foo(&s));
+ assert_eq!(1, s.foo());
+ assert_eq!(2, Box::new(s).bar());
+ assert_eq!(4, S::baz((2, 2)));
+}
diff --git a/tests/ui/delegation/explicit-paths-signature-pass.stderr b/tests/ui/delegation/explicit-paths-signature-pass.stderr
new file mode 100644
index 0000000000000..6c81a2ea0af73
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths-signature-pass.stderr
@@ -0,0 +1,11 @@
+warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/explicit-paths-signature-pass.rs:3:12
+ |
+LL | #![feature(fn_delegation)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #118212 for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/delegation/explicit-paths.rs b/tests/ui/delegation/explicit-paths.rs
new file mode 100644
index 0000000000000..1feaaa73f79e8
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths.rs
@@ -0,0 +1,25 @@
+#![feature(fn_delegation)]
+//~^ WARN the feature `fn_delegation` is incomplete
+
+trait Trait {
+ fn bar(&self) -> i32 { 42 }
+}
+
+struct F;
+impl Trait for F {}
+
+struct S(F);
+
+impl Trait for S {
+ reuse ::bar;
+ //~^ ERROR mismatched types
+}
+
+struct S2(F);
+
+impl Trait for S2 {
+ reuse ::bar { &self.0 }
+ //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr
new file mode 100644
index 0000000000000..2994b2390dedf
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths.stderr
@@ -0,0 +1,38 @@
+warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/explicit-paths.rs:1:12
+ |
+LL | #![feature(fn_delegation)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #118212 for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+ --> $DIR/explicit-paths.rs:14:25
+ |
+LL | reuse ::bar;
+ | --------------^^^
+ | | |
+ | | expected `&F`, found `&S`
+ | arguments to this function are incorrect
+ |
+ = note: expected reference `&F`
+ found reference `&S`
+note: method defined here
+ --> $DIR/explicit-paths.rs:5:8
+ |
+LL | fn bar(&self) -> i32 { 42 }
+ | ^^^ -----
+
+error[E0308]: mismatched types
+ --> $DIR/explicit-paths.rs:21:32
+ |
+LL | reuse ::bar { &self.0 }
+ | ^^^^^^^ expected `&S2`, found `&F`
+ |
+ = note: expected reference `&S2`
+ found reference `&F`
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs
new file mode 100644
index 0000000000000..23081b1e1fc8b
--- /dev/null
+++ b/tests/ui/delegation/not-supported.rs
@@ -0,0 +1,111 @@
+#![feature(c_variadic)]
+#![feature(fn_delegation)]
+//~^ WARN the feature `fn_delegation` is incomplete
+
+mod generics {
+ trait GenericTrait {
+ 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(&self, x: T) -> T { x }
+ fn foo3<'a: 'a>(_: &'a u32) {}
+
+ reuse GenericTrait::bar;
+ //~^ delegation with early bound generics is not supported yet
+ reuse GenericTrait::bar1;
+ //~^ delegation with early bound generics is not supported yet
+ }
+
+ struct F;
+ impl Trait for F {}
+ impl GenericTrait for F {}
+
+ struct S(F);
+
+ impl GenericTrait for S {
+ reuse >::bar { &self.0 }
+ //~^ ERROR delegation with early bound generics is not supported yet
+ reuse GenericTrait::::bar1;
+ //~^ ERROR delegation with early bound generics is not supported yet
+ }
+
+ impl GenericTrait<()> for () {
+ reuse GenericTrait::bar { &F }
+ //~^ ERROR delegation with early bound generics is not supported yet
+ reuse GenericTrait::bar1;
+ //~^ ERROR delegation with early bound generics is not supported yet
+ }
+
+ impl Trait for &S {
+ reuse Trait::foo;
+ //~^ ERROR delegation with early bound generics is not supported yet
+ }
+
+ 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 method `foo2` has 0 type parameters but its trait declaration has 1 type parameter
+ reuse ::foo3;
+ //~^ ERROR delegation with early bound generics is not supported yet
+ //~| ERROR lifetime parameters or bounds on method `foo3` do not match the trait declaration
+ }
+
+ struct GenericS(T);
+ impl Trait for GenericS {
+ reuse Trait::foo { &self.0 }
+ //~^ ERROR delegation with early bound generics is not supported yet
+ }
+}
+
+mod opaque {
+ trait Trait {}
+ impl Trait for () {}
+
+ mod to_reuse {
+ use super::Trait;
+
+ pub fn opaque_arg(_: impl Trait) -> i32 { 0 }
+ pub fn opaque_ret() -> impl Trait { unimplemented!() }
+ }
+ reuse to_reuse::opaque_arg;
+ //~^ ERROR delegation with early bound generics is not supported yet
+ reuse to_reuse::opaque_ret;
+ //~^ ERROR delegation to a function with opaque type is not supported yet
+}
+
+mod fn_header {
+ mod to_reuse {
+ pub unsafe fn unsafe_fn() {}
+ pub extern "C" fn extern_fn() {}
+ pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {}
+ pub const fn const_fn() {}
+ }
+
+ reuse to_reuse::unsafe_fn;
+ //~^ ERROR delegation to unsafe functions is not supported yet
+ reuse to_reuse::extern_fn;
+ //~^ ERROR delegation to non Rust ABI functions is not supported yet
+ reuse to_reuse::variadic_fn;
+ //~^ ERROR delegation to variadic functions is not supported yet
+ reuse to_reuse::const_fn;
+ //~^ ERROR delegation to const functions is not supported yet
+}
+
+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
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr
new file mode 100644
index 0000000000000..f235767d50afc
--- /dev/null
+++ b/tests/ui/delegation/not-supported.stderr
@@ -0,0 +1,184 @@
+warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/not-supported.rs:2:12
+ |
+LL | #![feature(fn_delegation)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #118212 for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:16:29
+ |
+LL | fn bar(&self, x: T) -> T { x }
+ | ------------------------ callee defined here
+...
+LL | reuse GenericTrait::bar;
+ | ^^^
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:18:29
+ |
+LL | fn bar1() {}
+ | --------- callee defined here
+...
+LL | reuse GenericTrait::bar1;
+ | ^^^^
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:29:39
+ |
+LL | fn bar(&self, x: T) -> T { x }
+ | ------------------------ callee defined here
+...
+LL | reuse >::bar { &self.0 }
+ | ^^^
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:31:34
+ |
+LL | fn bar1() {}
+ | --------- callee defined here
+...
+LL | reuse GenericTrait::::bar1;
+ | ^^^^
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:36:29
+ |
+LL | fn bar(&self, x: T) -> T { x }
+ | ------------------------ callee defined here
+...
+LL | reuse GenericTrait::bar { &F }
+ | ^^^
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:38:29
+ |
+LL | fn bar1() {}
+ | --------- callee defined here
+...
+LL | reuse GenericTrait::bar1;
+ | ^^^^
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:43:22
+ |
+LL | fn foo(&self, x: i32) -> i32 { x }
+ | ---------------------------- callee defined here
+...
+LL | reuse Trait::foo;
+ | ^^^
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:49:22
+ |
+LL | fn foo2(&self, x: T) -> T { x }
+ | ---------------------------- callee defined here
+...
+LL | reuse Trait::foo2 { &self.0 }
+ | ^^^^
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:52:29
+ |
+LL | fn foo3<'a: 'a>(_: &'a u32) {}
+ | --------------------------- callee defined here
+...
+LL | reuse ::foo3;
+ | ^^^^
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:59:22
+ |
+LL | fn foo(&self, x: i32) -> i32 { x }
+ | ---------------------------- callee defined here
+...
+LL | reuse Trait::foo { &self.0 }
+ | ^^^
+
+error: delegation with early bound generics is not supported yet
+ --> $DIR/not-supported.rs:74:21
+ |
+LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 }
+ | --------------------------------------- callee defined here
+...
+LL | reuse to_reuse::opaque_arg;
+ | ^^^^^^^^^^
+
+error: delegation to a function with opaque type is not supported yet
+ --> $DIR/not-supported.rs:76:21
+ |
+LL | pub fn opaque_ret() -> impl Trait { unimplemented!() }
+ | --------------------------------- callee defined here
+...
+LL | reuse to_reuse::opaque_ret;
+ | ^^^^^^^^^^
+
+error: delegation to unsafe functions is not supported yet
+ --> $DIR/not-supported.rs:88:21
+ |
+LL | pub unsafe fn unsafe_fn() {}
+ | ------------------------- callee defined here
+...
+LL | reuse to_reuse::unsafe_fn;
+ | ^^^^^^^^^
+
+error: delegation to non Rust ABI functions is not supported yet
+ --> $DIR/not-supported.rs:90:21
+ |
+LL | pub extern "C" fn extern_fn() {}
+ | ----------------------------- callee defined here
+...
+LL | reuse to_reuse::extern_fn;
+ | ^^^^^^^^^
+
+error: delegation to variadic functions is not supported yet
+ --> $DIR/not-supported.rs:92:21
+ |
+LL | pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {}
+ | ------------------------------------------------------------- callee defined here
+...
+LL | reuse to_reuse::variadic_fn;
+ | ^^^^^^^^^^^
+
+error: delegation to const functions is not supported yet
+ --> $DIR/not-supported.rs:94:21
+ |
+LL | pub const fn const_fn() {}
+ | ----------------------- callee defined here
+...
+LL | reuse to_reuse::const_fn;
+ | ^^^^^^^^
+
+error: recursive delegation is not supported yet
+ --> $DIR/not-supported.rs:107:22
+ |
+LL | pub reuse to_reuse2::foo;
+ | --- callee defined here
+...
+LL | reuse to_reuse1::foo;
+ | ^^^
+
+error[E0049]: method `foo2` has 0 type parameters but its trait declaration has 1 type parameter
+ --> $DIR/not-supported.rs:49:22
+ |
+LL | fn foo2(&self, x: T) -> T { x }
+ | - expected 1 type parameter
+...
+LL | reuse Trait::foo2 { &self.0 }
+ | ^^^^ found 0 type parameters
+
+error[E0195]: lifetime parameters or bounds on method `foo3` do not match the trait declaration
+ --> $DIR/not-supported.rs:52:29
+ |
+LL | fn foo3<'a: 'a>(_: &'a u32) {}
+ | -------- lifetimes in impl do not match this method in trait
+...
+LL | reuse ::foo3;
+ | ^^^^ lifetimes do not match method in trait
+
+error: aborting due to 19 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0049, E0195.
+For more information about an error, try `rustc --explain E0049`.
diff --git a/tests/ui/delegation/parse.rs b/tests/ui/delegation/parse.rs
new file mode 100644
index 0000000000000..791cc1630ff7d
--- /dev/null
+++ b/tests/ui/delegation/parse.rs
@@ -0,0 +1,42 @@
+// check-pass
+
+#![feature(decl_macro)]
+#![feature(fn_delegation)]
+//~^ WARN the feature `fn_delegation` is incomplete
+
+macro_rules! reuse { {} => {} }
+
+mod reuse {
+ pub fn to_unsafe(x: i32) -> i32 { x + 1 }
+ pub fn to_pub() {}
+ pub fn to_pub2() {}
+
+ mod inner {
+ #[allow(non_camel_case_types)]
+ struct reuse {
+ a: i32,
+ b: i32,
+ c: i32,
+ }
+
+ impl reuse {
+ reuse!();
+ }
+
+ fn baz() {
+ let (a, b, c) = (0, 0, 0);
+ reuse {a, b, c};
+ }
+ }
+
+ pub macro my_macro() {}
+}
+
+reuse!();
+reuse::my_macro!();
+
+#[inline]
+pub reuse reuse::to_pub;
+pub reuse crate::reuse::to_pub2;
+
+fn main() {}
diff --git a/tests/ui/delegation/parse.stderr b/tests/ui/delegation/parse.stderr
new file mode 100644
index 0000000000000..1e420ceeec7f1
--- /dev/null
+++ b/tests/ui/delegation/parse.stderr
@@ -0,0 +1,11 @@
+warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/parse.rs:4:12
+ |
+LL | #![feature(fn_delegation)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #118212 for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/delegation/target-expr-pass.rs b/tests/ui/delegation/target-expr-pass.rs
new file mode 100644
index 0000000000000..56068dfce01d7
--- /dev/null
+++ b/tests/ui/delegation/target-expr-pass.rs
@@ -0,0 +1,37 @@
+// run-pass
+
+#![feature(fn_delegation)]
+//~^ WARN the feature `fn_delegation` is incomplete
+
+mod to_reuse {
+ pub fn foo(x: i32) -> i32 { x }
+ pub mod inner {}
+}
+
+reuse to_reuse::foo {{
+ use self::to_reuse::foo;
+ let x = foo(12);
+ x + self
+}}
+
+trait Trait {
+ fn bar(&self, x: i32) -> i32 { x }
+}
+
+struct F;
+impl Trait for F {}
+
+struct S(F);
+impl Trait for S {
+ reuse ::bar {
+ #[allow(unused_imports)]
+ use self::to_reuse::{foo, inner::self};
+ let x = foo(12);
+ assert_eq!(x, 12);
+ &self.0
+ }
+}
+
+fn main() {
+ assert_eq!(foo(12), 24);
+}
diff --git a/tests/ui/delegation/target-expr-pass.stderr b/tests/ui/delegation/target-expr-pass.stderr
new file mode 100644
index 0000000000000..ea594f8a26a5b
--- /dev/null
+++ b/tests/ui/delegation/target-expr-pass.stderr
@@ -0,0 +1,11 @@
+warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/target-expr-pass.rs:3:12
+ |
+LL | #![feature(fn_delegation)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #118212 for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/feature-gates/feature-gate-fn_delegation.rs b/tests/ui/feature-gates/feature-gate-fn_delegation.rs
index 6ac3671209033..5352b2d8cadb4 100644
--- a/tests/ui/feature-gates/feature-gate-fn_delegation.rs
+++ b/tests/ui/feature-gates/feature-gate-fn_delegation.rs
@@ -1,3 +1,8 @@
-todo!(); //~ ERROR
+mod to_reuse {
+ pub fn foo() {}
+}
+
+reuse to_reuse::foo;
+//~^ ERROR functions delegation is not yet fully implemented
fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-fn_delegation.stderr b/tests/ui/feature-gates/feature-gate-fn_delegation.stderr
index 14d85c5263e0d..9b62e4ecff44f 100644
--- a/tests/ui/feature-gates/feature-gate-fn_delegation.stderr
+++ b/tests/ui/feature-gates/feature-gate-fn_delegation.stderr
@@ -1,13 +1,12 @@
-error: expected one of `!` or `::`, found `(`
- --> $DIR/feature-gate-fn_delegation.rs:1:1
+error[E0658]: functions delegation is not yet fully implemented
+ --> $DIR/feature-gate-fn_delegation.rs:5:1
|
-LL | todo!();
- | ^^^^^^^
- | |
- | expected one of `!` or `::`
- | in this macro invocation
+LL | reuse to_reuse::foo;
+ | ^^^^^^^^^^^^^^^^^^^^
|
- = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: see issue #118212 for more information
+ = help: add `#![feature(fn_delegation)]` to the crate attributes to enable
error: aborting due to 1 previous error
+For more information about this error, try `rustc --explain E0658`.