diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 5755ae8a8bc47..a1cfa9827ebe7 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2978,6 +2978,14 @@ pub struct Fn {
pub body: Option
>,
}
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Delegation {
+ pub id: NodeId,
+ pub path: (Option
>, Path),
+ pub target_expr: Option
>,
+ pub span: Span,
+}
+
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct StaticItem {
pub ty: P,
@@ -3063,6 +3071,11 @@ pub enum ItemKind {
/// A macro definition.
MacroDef(MacroDef),
+
+ /// A delegation item (`reuse`).
+ ///
+ /// E.g. reuse ::name { target_expr_template }
+ Delegation(Box),
}
impl ItemKind {
@@ -3070,7 +3083,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",
}
}
@@ -3094,6 +3108,7 @@ impl ItemKind {
ItemKind::MacCall(..) => "item macro invocation",
ItemKind::MacroDef(..) => "macro definition",
ItemKind::Impl { .. } => "implementation",
+ ItemKind::Delegation(..) => "delegation",
}
}
@@ -3135,6 +3150,8 @@ pub enum AssocItemKind {
Type(Box),
/// A macro expanding to associated items.
MacCall(P),
+ /// An associated delegation item.
+ Delegation(Box),
}
impl AssocItemKind {
@@ -3143,7 +3160,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,
}
}
}
@@ -3155,6 +3172,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),
}
}
}
@@ -3168,6 +3186,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/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index 4dc9c30a2c807..2b5377c3457dd 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -5,7 +5,7 @@
use crate::ptr::P;
use crate::token::Nonterminal;
use crate::tokenstream::LazyAttrTokenStream;
-use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
+use crate::{Arm, Crate, Delegation, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
use crate::{AssocItem, Expr, ForeignItem, Item, NodeId};
use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
use crate::{AttrVec, Attribute, Stmt, StmtKind};
@@ -80,6 +80,7 @@ impl_has_node_id!(
Stmt,
Ty,
Variant,
+ Delegation
);
impl> HasNodeId for T {
@@ -108,7 +109,19 @@ macro_rules! impl_has_span {
};
}
-impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility);
+impl_has_span!(
+ AssocItem,
+ Block,
+ Expr,
+ ForeignItem,
+ Item,
+ Pat,
+ Path,
+ Stmt,
+ Ty,
+ Visibility,
+ Delegation
+);
impl> HasSpan for T {
fn span(&self) -> Span {
@@ -159,7 +172,7 @@ macro_rules! impl_has_tokens_none {
}
impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility);
-impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant);
+impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant, Delegation);
impl> HasTokens for T {
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 10b2025f93783..d16c2ee7aa1bf 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) => {
+ vis.visit_id(&mut delegation.id);
+ vis.visit_qself(&mut delegation.path.0);
+ vis.visit_path(&mut delegation.path.1);
+ if let Some(target_expr) = &mut delegation.target_expr {
+ vis.visit_expr(target_expr);
+ }
+ }
}
}
@@ -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) => {
+ visitor.visit_id(&mut delegation.id);
+ visitor.visit_qself(&mut delegation.path.0);
+ visitor.visit_path(&mut delegation.path.1);
+ if let Some(target_expr) = &mut delegation.target_expr {
+ visitor.visit_expr(target_expr);
+ }
+ }
}
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 27f1b84f37251..2fca9724bbac3 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) => {
+ if let Some(qself) = &delegation.path.0 {
+ visitor.visit_ty(&qself.ty);
+ }
+ walk_path(visitor, &delegation.path.1);
+ if let Some(target_expr) = &delegation.target_expr {
+ visitor.visit_expr(target_expr);
+ }
+ }
}
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) => {
+ if let Some(qself) = &delegation.path.0 {
+ visitor.visit_ty(&qself.ty);
+ }
+ walk_path(visitor, &delegation.path.1);
+ if let Some(target_expr) = &delegation.target_expr {
+ visitor.visit_expr(target_expr);
+ }
+ }
}
}
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
new file mode 100644
index 0000000000000..97b0792e9e529
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -0,0 +1,277 @@
+use crate::{ImplTraitPosition, ResolverAstLoweringExt};
+
+use super::{ImplTraitContext, LoweringContext, ParamMode};
+
+use ast::visit::Visitor;
+use hir::def::DefKind;
+use hir::def::PartialRes;
+use hir::{BodyId, HirId};
+use rustc_ast as ast;
+use rustc_ast::*;
+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::kw;
+use rustc_span::{symbol::Ident, Span};
+use rustc_target::spec::abi;
+use std::iter;
+
+pub struct DelegationResults<'hir> {
+ pub body_id: hir::BodyId,
+ pub sig: hir::FnSig<'hir>,
+ pub generics: &'hir hir::Generics<'hir>,
+}
+
+impl<'hir> LoweringContext<'_, 'hir> {
+ pub fn delegation_has_self(&self, delegation: &Delegation) -> bool {
+ let res_id = self.get_delegation_res_id(delegation.id);
+ let Some(res_id) = res_id else {
+ self.tcx.sess.span_delayed_bug(
+ delegation.span,
+ "LoweringContext: couldn't resolve delegation item",
+ );
+ return false;
+ };
+
+ if let Some(local_res_id) = res_id.as_local() {
+ self.resolver.has_self.contains(&local_res_id)
+ } else {
+ match self.tcx.def_kind(res_id) {
+ DefKind::Fn => false,
+ DefKind::AssocFn => self.tcx.associated_item(res_id).fn_has_self_parameter,
+ _ => span_bug!(delegation.span, "unexpected DefKind for delegation item"),
+ }
+ }
+ }
+
+ pub fn lower_delegation(&mut self, delegation: &Delegation) -> DelegationResults<'hir> {
+ let res_id = self.get_delegation_res_id(delegation.id);
+ let Some(res_id) = res_id else {
+ self.tcx.sess.span_delayed_bug(
+ delegation.span,
+ "LoweringContext: couldn't resolve delegation item",
+ );
+ return self.generate_delegation_error(delegation);
+ };
+
+ let decl = self.lower_delegation_decl(res_id, delegation.span);
+ let sig = self.lower_delegation_sig(delegation.span, decl);
+ let body_id = self.lower_delegation_body(sig.decl, delegation);
+
+ let generics = self.lower_delegation_generics(delegation.span);
+ DelegationResults { body_id, sig, generics }
+ }
+
+ fn get_delegation_res_id(&self, node_id: NodeId) -> Option {
+ self.resolver.get_partial_res(node_id).map(|r| r.base_res().opt_def_id()).unwrap_or(None)
+ }
+
+ fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
+ self.arena.alloc(hir::Generics {
+ params: self.arena.alloc_from_iter([]),
+ predicates: self.arena.alloc_from_iter([]),
+ has_where_clause_predicates: false,
+ where_clause_span: span,
+ span,
+ })
+ }
+
+ fn lower_delegation_decl(&mut self, res_id: DefId, span: Span) -> &'hir hir::FnDecl<'hir> {
+ let args_count = if res_id.is_local() {
+ self.resolver.fns_arguments_count[&res_id]
+ } else {
+ self.tcx.fn_arg_names(res_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(res_id, hir::InferDelegationVar::Input(arg)),
+ span,
+ }));
+
+ let output = self.arena.alloc(hir::Ty {
+ hir_id: self.next_id(),
+ kind: hir::TyKind::InferDelegation(res_id, hir::InferDelegationVar::Output),
+ 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: hir::def::Res::Local(param_id),
+ args: None,
+ infer_args: false,
+ }));
+
+ let path = self.arena.alloc(hir::Path {
+ span: ty.span,
+ res: hir::def::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 (qself, path) = &delegation.path;
+ let path = self.lower_qpath(
+ delegation.id,
+ qself,
+ path,
+ ParamMode::Optional,
+ &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
+ );
+ let expr = delegation.target_expr.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);
+
+ if idx != 0 || expr.is_none() {
+ let pat_hir_id = this.lower_node_id(pat_node_id);
+ let arg = this.generate_arg(param_ty, pat_hir_id);
+ args.push(arg);
+ } else {
+ let expr = expr.unwrap();
+ let mut self_resolver =
+ SelfResolver { res_id: pat_node_id, resolver: this.resolver };
+ self_resolver.visit_expr(expr);
+ let target_expr = this.lower_expr_mut(expr);
+ args.push(target_expr);
+ };
+ }
+
+ 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: self.arena.alloc_from_iter([]),
+ 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, delegation: &Delegation) -> DelegationResults<'hir> {
+ let generics = self.lower_delegation_generics(delegation.span);
+
+ let decl = self.arena.alloc(hir::FnDecl {
+ inputs: self.arena.alloc_from_iter([]),
+ output: hir::FnRetTy::DefaultReturn(delegation.span),
+ c_variadic: false,
+ lifetime_elision_allowed: true,
+ implicit_self: hir::ImplicitSelfKind::None,
+ });
+
+ let sig = self.lower_delegation_sig(delegation.span, decl);
+ let body_id = self.lower_body(|this| {
+ let err = this.tcx.sess.span_delayed_bug(
+ delegation.span,
+ "LoweringContext: couldn't resolve delegation item",
+ );
+ let expr = hir::Expr {
+ hir_id: this.next_id(),
+ kind: hir::ExprKind::Err(err),
+ span: delegation.span,
+ };
+ (this.arena.alloc_from_iter([]), expr)
+ });
+ DelegationResults { generics, body_id, sig }
+ }
+}
+
+struct SelfResolver<'a> {
+ resolver: &'a mut ResolverAstLowering,
+ res_id: NodeId,
+}
+
+impl<'ast, 'a> ast::visit::Visitor<'ast> for SelfResolver<'a> {
+ fn visit_path(&mut self, path: &'ast Path, id: NodeId) {
+ if path.segments.len() == 1 && path.segments[0].ident.name == kw::SelfLower {
+ let res = PartialRes::new(hir::def::Res::Local(self.res_id));
+ self.resolver.partial_res_map.insert(id, res);
+ self.resolver.partial_res_map.insert(path.segments[0].id, res);
+ }
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 7c05724f64c95..3cba35da7d9c8 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -427,6 +427,16 @@ 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) => self.with_new_scopes(ident.span, |this| {
+ this.current_item = Some(ident.span);
+
+ let delegation_results = this.lower_delegation(delegation);
+ hir::ItemKind::Fn(
+ delegation_results.sig,
+ delegation_results.generics,
+ delegation_results.body_id,
+ )
+ }),
ItemKind::MacCall(..) => {
panic!("`TyMac` should have been expanded by now")
}
@@ -787,6 +797,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
(generics, kind, ty.is_some())
}
+ AssocItemKind::Delegation(box delegation) => {
+ let delegation_results = self.lower_delegation(delegation);
+ (
+ delegation_results.generics,
+ hir::TraitItemKind::Fn(
+ delegation_results.sig,
+ hir::TraitFn::Provided(delegation_results.body_id),
+ ),
+ true,
+ )
+ }
AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
};
@@ -808,6 +829,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(delegation) }
+ }
AssocItemKind::MacCall(..) => unimplemented!(),
};
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
@@ -890,6 +914,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
},
)
}
+ AssocItemKind::Delegation(box delegation) => {
+ let delegation_results = self.lower_delegation(delegation);
+ (
+ delegation_results.generics,
+ hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
+ )
+ }
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
};
@@ -916,6 +947,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(delegation) }
+ }
AssocItemKind::MacCall(..) => unimplemented!(),
},
trait_item_def_id: self
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d9663d50c595c..1db967a73705d 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -78,6 +78,7 @@ macro_rules! arena_vec {
mod asm;
mod block;
+mod delegation;
mod errors;
mod expr;
mod format;
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index ea5d22a344877..e22759ae31364 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -2,7 +2,7 @@ use crate::pp::Breaks::Inconsistent;
use crate::pprust::state::expr::FixupContext;
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
-use ast::StaticItem;
+use ast::{AstDeref, StaticItem};
use itertools::{Itertools, Position};
use rustc_ast as ast;
use rustc_ast::GenericBound;
@@ -387,6 +387,7 @@ impl<'a> State<'a> {
state.print_visibility(&item.vis)
});
}
+ ast::ItemKind::Delegation(box delegation) => self.print_delegation(delegation),
}
self.ann.post(self, AnnNode::Item(item))
}
@@ -565,10 +566,33 @@ impl<'a> State<'a> {
self.word(";");
}
}
+ ast::AssocItemKind::Delegation(box delegation) => self.print_delegation(delegation),
}
self.ann.post(self, AnnNode::SubItem(id))
}
+ pub(crate) fn print_delegation(&mut self, delegation: &ast::Delegation) {
+ self.ibox(0);
+ self.word_space("reuse");
+ let (qself, path, expr) = (&delegation.path.0, &delegation.path.1, &delegation.target_expr);
+
+ if let Some(qself) = qself {
+ self.print_qpath(path, qself.ast_deref(), false);
+ } else {
+ self.print_path(path, false, 0);
+ }
+ self.space();
+ if let Some(target_expr) = expr {
+ self.word_space("{");
+ self.print_expr(target_expr.ast_deref(), FixupContext::default());
+ self.word(" }");
+ } else {
+ self.word(";");
+ }
+
+ self.end();
+ }
+
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 01508375b1ace..c42615e08bdfa 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2526,9 +2526,16 @@ pub enum OpaqueTyOrigin {
},
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)]
+pub enum InferDelegationVar {
+ Input(usize),
+ Output,
+}
+
/// The various kinds of types recognized by the compiler.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TyKind<'hir> {
+ InferDelegation(DefId, InferDelegationVar),
/// 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 9cf1db166a581..ab5b0c44c5ca8 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -861,7 +861,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 139e1c0ac5fdc..6536cf19197cd 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 =
+ delegation to {$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 caae6fa4f065e..7d7fafbe5f1ef 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2405,6 +2405,109 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.ast_ty_to_ty_inner(ast_ty, false, true)
}
+ fn check_delegation_constraints(&self, res_id: DefId, span: Span, emit: bool) -> bool {
+ let mut error_occured = false;
+ let mut try_emit = |error| {
+ if emit {
+ self.tcx().sess.emit_err(error);
+ }
+ error_occured = true;
+ };
+ let res_span = self.tcx().def_span(res_id);
+
+ let res_generics = self.tcx().generics_of(res_id);
+ let parent = self.tcx().parent(self.item_def_id());
+ let parent_generics = self.tcx().generics_of(parent);
+ let self_ty_bias = (self.tcx().def_kind(parent) == DefKind::Trait) as usize;
+ if parent_generics.count() + res_generics.own_counts().count() > self_ty_bias {
+ try_emit(super::errors::NotSupportedDelegation {
+ span,
+ descr: "generic function",
+ res_span,
+ });
+ }
+ if self.tcx().asyncness(res_id) == ty::Asyncness::Yes {
+ try_emit(super::errors::NotSupportedDelegation {
+ span,
+ descr: "async function",
+ res_span,
+ });
+ }
+
+ if self.tcx().constness(res_id) == hir::Constness::Const {
+ try_emit(super::errors::NotSupportedDelegation {
+ span,
+ descr: "const function",
+ res_span,
+ });
+ }
+
+ let res_sig = self.tcx().fn_sig(res_id).instantiate_identity();
+ if res_sig.c_variadic() {
+ try_emit(super::errors::NotSupportedDelegation {
+ span,
+ descr: "variadic function",
+ res_span,
+ });
+ return error_occured;
+ }
+
+ if let hir::Unsafety::Unsafe = res_sig.unsafety() {
+ try_emit(super::errors::NotSupportedDelegation {
+ span,
+ descr: "unsafe function",
+ res_span,
+ });
+ }
+
+ if abi::Abi::Rust != res_sig.abi() {
+ try_emit(super::errors::NotSupportedDelegation {
+ span,
+ descr: "function with non Rust ABI",
+ res_span,
+ });
+ }
+
+ error_occured
+ }
+
+ fn ty_from_delegation(
+ &self,
+ res_id: DefId,
+ idx: hir::InferDelegationVar,
+ span: Span,
+ ) -> Ty<'tcx> {
+ if self.check_delegation_constraints(res_id, span, idx == hir::InferDelegationVar::Output) {
+ let e = self.tcx().sess.span_delayed_bug(span, "not supported delegation case");
+ self.set_tainted_by_errors(e);
+ return Ty::new_error(self.tcx(), e);
+ };
+ let res_sig = self.tcx().fn_sig(res_id);
+
+ let parent = self.tcx().parent(self.item_def_id());
+ let item_def_kind = self.tcx().def_kind(self.item_def_id());
+ let parent_def_kind = self.tcx().def_kind(parent);
+
+ let res_sig = match (item_def_kind, parent_def_kind) {
+ (DefKind::AssocFn, DefKind::Impl { of_trait: true }) => {
+ 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));
+ res_sig.instantiate(self.tcx(), substs).skip_binder()
+ }
+ (DefKind::Fn, _) | (DefKind::AssocFn, _) => {
+ res_sig.instantiate_identity().skip_binder()
+ }
+ _ => span_bug!(span, "ty_from_delegation: couldn't calculate resolution signature"),
+ };
+
+ if let hir::InferDelegationVar::Input(id) = idx {
+ res_sig.inputs()[id]
+ } else {
+ res_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)]
@@ -2412,6 +2515,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let tcx = self.tcx();
let result_ty = match &ast_ty.kind {
+ hir::TyKind::InferDelegation(res_id, idx) => {
+ self.ty_from_delegation(*res_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 })
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index a47722936975e..8dbe3c3e4f931 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1411,3 +1411,13 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> {
pub mut_key: &'a str,
pub ptr_ty: Ty<'a>,
}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_not_supported_delegation)]
+pub struct NotSupportedDelegation<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub descr: &'a str,
+ #[label]
+ pub res_span: Span,
+}
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 8701626058d43..0068461d32590 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/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index c3699b114c411..61110e85fce03 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -122,6 +122,12 @@ pub struct GenericParamCount {
pub consts: usize,
}
+impl GenericParamCount {
+ pub fn count(&self) -> usize {
+ self.lifetimes + self.types + self.consts
+ }
+}
+
/// Information about the formal type/lifetime parameters associated
/// with an item or method. Analogous to `hir::Generics`.
///
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 71ff7021ca5de..126dc58f30782 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -41,7 +41,7 @@ use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
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;
@@ -201,6 +201,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 fns_arguments_count: FxHashMap,
}
#[derive(Clone, Copy, Debug)]
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 89919247e8228..339bfdbad67fd 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -255,6 +255,8 @@ impl<'a> Parser<'a> {
{
// IMPL ITEM
self.parse_item_impl(attrs, def_())?
+ } else if self.check_keyword(kw::Reuse) {
+ self.parse_item_delegation()?
} else if self.check_keyword(kw::Mod)
|| self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod])
{
@@ -352,11 +354,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 {
+ self.is_kw_followed_by_ident(kw::Reuse) // no: `reuse::b`, yes: `reuse U::`
+ // no: `reuse::b`, yes: reuse ::
+ || (self.token.is_keyword(kw::Reuse) && self.look_ahead(1, |t| *t == token::Lt))
+ }
+
/// 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)
@@ -658,6 +667,39 @@ impl<'a> Parser<'a> {
Ok((Ident::empty(), item_kind))
}
+ fn parse_item_delegation(&mut self) -> PResult<'a, ItemInfo> {
+ self.expect_keyword(kw::Reuse)?;
+ let span = self.prev_token.span;
+
+ 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 expr = if self.eat(&token::OpenDelim(Delimiter::Brace)) {
+ let expr = self.parse_expr()?;
+ self.expect(&token::CloseDelim(Delimiter::Brace))?;
+ Some(expr)
+ } else {
+ self.expect(&token::Semi)?;
+ None
+ };
+
+ let ident =
+ path.segments.last().and_then(|segment| Some(segment.ident)).unwrap_or(Ident::empty());
+ Ok((
+ ident,
+ ItemKind::Delegation(Box::new(Delegation {
+ id: DUMMY_NODE_ID,
+ path: (qself, path),
+ target_expr: expr,
+ span: span.to(self.prev_token.span),
+ })),
+ ))
+ }
+
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 85969b72d2397..a6bb675d08fcd 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_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 213b320ed1a66..65440f3e51a78 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -788,6 +788,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
ItemKind::Impl(box Impl { of_trait: Some(..), .. }) => {
self.r.trait_impl_items.insert(local_def_id);
}
+
+ ItemKind::Delegation(..) => {
+ let res = Res::Def(DefKind::Fn, def_id);
+ self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
+ }
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
ItemKind::MacroDef(..) | ItemKind::MacCall(_) => unreachable!(),
@@ -1367,6 +1372,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
ValueNS
}
AssocItemKind::Type(..) => TypeNS,
+ AssocItemKind::Delegation(..) => ValueNS,
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..b7f90c93a5758 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -112,6 +112,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
ItemKind::Static(s) => DefKind::Static(s.mutability),
ItemKind::Const(..) => DefKind::Const,
ItemKind::Fn(..) => DefKind::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();
@@ -154,8 +155,12 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
});
}
- fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
+ fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, fn_id: NodeId) {
if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
+ self.resolver
+ .fns_arguments_count
+ .insert(self.resolver.node_id_to_def_id[&fn_id].to_def_id(), sig.decl.inputs.len());
+
match sig.header.coroutine_kind {
Some(coroutine_kind) => {
self.visit_generics(generics);
@@ -262,6 +267,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
AssocItemKind::Fn(..) => DefKind::AssocFn,
AssocItemKind::Const(..) => DefKind::AssocConst,
AssocItemKind::Type(..) => DefKind::AssocTy,
+ AssocItemKind::Delegation(..) => DefKind::AssocFn,
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 a71c50dd82fdd..8cc6ef30dd2a1 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 9c96e9a9bd728..a07a69da60463 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, _)),
}
}
@@ -539,6 +546,7 @@ impl<'a> PathSource<'a> {
(PathSource::Pat | PathSource::TupleStruct(..), false) => error_code!(E0531),
(PathSource::TraitItem(..), true) => error_code!(E0575),
(PathSource::TraitItem(..), false) => error_code!(E0576),
+ (PathSource::Delegation, _) => error_code!(E0795),
}
}
}
@@ -673,6 +681,8 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
/// If it is `true`, then it will be updated when entering a nested function or trait body.
in_func_body: bool,
+ in_delegation_item: bool,
+
/// Count the number of places a lifetime is used.
lifetime_uses: FxHashMap,
}
@@ -896,6 +906,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
}
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
let previous_value = self.diagnostic_metadata.current_function;
+
match fn_kind {
// Bail if the function is foreign, and thus cannot validly have
// a body, or if there's no body for some other reason.
@@ -1289,6 +1300,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
diagnostic_metadata: Default::default(),
// errors at module scope should always be reported
in_func_body: false,
+ in_delegation_item: false,
lifetime_uses: Default::default(),
}
}
@@ -1331,6 +1343,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
opt_ns: Option, // `None` indicates a module path in import
finalize: Option,
) -> PathResult<'a> {
+ if self.in_delegation_item && path.len() == 1 && path[0].ident.name == kw::SelfLower {
+ return PathResult::NonModule(def::PartialRes::new(def::Res::Err));
+ }
+
self.r.resolve_path_with_ribs(
path,
opt_ns,
@@ -1805,7 +1821,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
@@ -2518,9 +2535,15 @@ 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!"),
+ ItemKind::MacCall(_) => {
+ panic!("unexpanded item in resolve!")
+ }
}
}
@@ -2794,13 +2817,14 @@ 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)
}),
- AssocItemKind::MacCall(_) => {
- panic!("unexpanded macro in resolve!")
- }
+ AssocItemKind::MacCall(_) => panic!("unexpanded assoc item in resolve!"),
};
}
@@ -3040,6 +3064,23 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
},
);
}
+ AssocItemKind::Delegation(box delegation) => {
+ debug!("resolve_implementation AssocItemKind::Delegation");
+ let emitted = self.check_trait_item(
+ item.id,
+ item.ident,
+ &item.kind,
+ ValueNS,
+ item.span,
+ seen_trait_items,
+ |i, s, c| MethodNotMemberOfTrait(i, s, c),
+ );
+
+ // do not emit same errors twice
+ if !emitted {
+ self.resolve_delegation(delegation);
+ }
+ }
AssocItemKind::MacCall(_) => {
panic!("unexpanded macro in resolve!")
}
@@ -3055,12 +3096,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
span: Span,
seen_trait_items: &mut FxHashMap,
err: F,
- ) where
+ ) -> bool
+ where
F: FnOnce(Ident, String, Option) -> ResolutionError<'a>,
{
// If there is a TraitRef in scope for an impl, then the method must be in the trait.
let Some((module, _)) = self.current_trait_ref else {
- return;
+ return false;
};
ident.span.normalize_to_macros_2_0_and_adjust(module.expansion);
let key = BindingKey::new(ident, ns);
@@ -3084,7 +3126,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
let path = &self.current_trait_ref.as_ref().unwrap().1.path;
let path_names = path_names_to_string(path);
self.report_error(span, err(ident, path_names, candidate));
- return;
+ return true;
};
let res = binding.res();
@@ -3100,7 +3142,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
trait_item_span: binding.span,
},
);
- return;
+ return false;
}
Entry::Vacant(entry) => {
entry.insert(span);
@@ -3110,9 +3152,10 @@ 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;
+ return false;
}
_ => {}
}
@@ -3123,6 +3166,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);
@@ -3136,6 +3180,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
trait_item_span: binding.span,
},
);
+ true
}
fn resolve_const_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) {
@@ -3146,6 +3191,21 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
})
}
+ fn resolve_delegation(&mut self, delegation: &'ast Delegation) {
+ self.in_delegation_item = true;
+
+ let (qself, path) = &delegation.path;
+ if let Some(qself) = &delegation.path.0 {
+ self.visit_ty(&qself.ty);
+ }
+ self.smart_resolve_path(delegation.id, qself, path, PathSource::Delegation);
+
+ if let Some(target_expr) = &delegation.target_expr {
+ self.visit_expr(target_expr);
+ }
+ self.in_delegation_item = false;
+ }
+
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| {
@@ -4572,7 +4632,8 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
| ItemKind::ExternCrate(..)
| ItemKind::MacroDef(..)
| ItemKind::GlobalAsm(..)
- | ItemKind::MacCall(..) => {}
+ | ItemKind::MacCall(..)
+ | ItemKind::Delegation(..) => {}
}
visit::walk_item(self, item)
}
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index d767ed74139ba..13cd260cd0382 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -221,6 +221,18 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let mut span_label = None;
let item_ident = path.last().unwrap().ident;
let item_span = item_ident.span;
+ if let PathSource::Delegation = source {
+ return BaseError {
+ msg: format!("couldn't resolve `{item_str}` in delegation item"),
+ fallback_label: "delegation is only supported yet for trait methods with explicit paths and free functions".to_string(),
+ span: item_span,
+ span_label,
+ could_be_expr: false,
+ suggestion: None,
+ module: None,
+ };
+ }
+
let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {
debug!(?self.diagnostic_metadata.current_impl_items);
debug!(?self.diagnostic_metadata.current_function);
@@ -435,7 +447,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
code,
);
+ // FIXME: suggestions do not supported yet for delegation item
+ if let PathSource::Delegation = source {
+ err.span_label(base_error.span, base_error.fallback_label);
+ return (err, Vec::new());
+ }
self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
+
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
if let Some((span, label)) = base_error.span_label {
@@ -1905,6 +1923,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)
@@ -1966,6 +1985,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 70e0eb12c01da..d8ee285017462 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1119,6 +1119,8 @@ pub struct Resolver<'a, 'tcx> {
doc_link_resolutions: FxHashMap,
doc_link_traits_in_scope: FxHashMap>,
all_macro_rules: FxHashMap,
+
+ fns_arguments_count: FxHashMap,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1446,6 +1448,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
doc_link_resolutions: Default::default(),
doc_link_traits_in_scope: Default::default(),
all_macro_rules: Default::default(),
+ fns_arguments_count: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1544,6 +1547,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,
+ fns_arguments_count: self.fns_arguments_count,
};
ResolverOutputs { global_ctxt, ast_lowering }
}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 0333b5f04c3bc..9ffeacd5bb91f 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -101,6 +101,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 28ea662eab378..35f0f55895b04 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1881,7 +1881,9 @@ 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::DelegationPlaceholder(..) => {
+ Infer
+ }
}
}
diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs
new file mode 100644
index 0000000000000..a1bc9534b27f9
--- /dev/null
+++ b/tests/ui/delegation/bad-resolve.rs
@@ -0,0 +1,44 @@
+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 {
+//~^ not all trait items implemented, missing: `Type`
+ reuse ::C;
+ //~^ ERROR item `C` is an associated method, which doesn't match its trait `Trait`
+ reuse ::Type;
+ //~^ ERROR item `Type` is an associated method, which doesn't match its trait `Trait`
+ reuse ::baz;
+ //~^ ERROR method `baz` is not a member of trait `Trait`
+ reuse ::bar;
+
+ reuse foo { &self.0 }
+ //~^ ERROR couldn't resolve `foo` in delegation item
+ //~| method `foo` has a `&self` declaration in the trait, but not in the impl
+ reuse F::foo { &self.0 }
+ //~^ ERROR couldn't resolve `foo` in delegation item
+ //~| ERROR duplicate definitions with name `foo`
+}
+
+impl S {
+ reuse F::foo { &self.0 }
+ //~^ ERROR couldn't resolve `foo` in delegation item
+}
+
+fn main() {
+
+}
diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr
new file mode 100644
index 0000000000000..f6dd9f2282fe9
--- /dev/null
+++ b/tests/ui/delegation/bad-resolve.stderr
@@ -0,0 +1,79 @@
+error[E0324]: item `C` is an associated method, which doesn't match its trait `Trait`
+ --> $DIR/bad-resolve.rs:21: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:23: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:25: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:32:5
+ |
+LL | fn foo(&self, x: i32) -> i32 { x }
+ | ---------------------------------- item in trait
+...
+LL | reuse foo { &self.0 }
+ | --------------------- previous definition here
+...
+LL | reuse F::foo { &self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
+
+error[E0795]: couldn't resolve `foo` in delegation item
+ --> $DIR/bad-resolve.rs:29:11
+ |
+LL | reuse foo { &self.0 }
+ | ^^^ delegation is only supported yet for trait methods with explicit paths and free functions
+
+error[E0795]: couldn't resolve `foo` in delegation item
+ --> $DIR/bad-resolve.rs:32:14
+ |
+LL | reuse F::foo { &self.0 }
+ | ^^^ delegation is only supported yet for trait methods with explicit paths and free functions
+
+error[E0795]: couldn't resolve `foo` in delegation item
+ --> $DIR/bad-resolve.rs:38:14
+ |
+LL | reuse F::foo { &self.0 }
+ | ^^^ delegation is only supported yet for trait methods with explicit paths and free functions
+
+error[E0186]: method `foo` has a `&self` declaration in the trait, but not in the impl
+ --> $DIR/bad-resolve.rs:29:5
+ |
+LL | fn foo(&self, x: i32) -> i32 { x }
+ | ---------------------------- `&self` used in trait
+...
+LL | reuse foo { &self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^ expected `&self` in impl
+
+error[E0046]: not all trait items implemented, missing: `Type`
+ --> $DIR/bad-resolve.rs:19:1
+ |
+LL | type Type;
+ | --------- `Type` from trait
+...
+LL | impl Trait for S {
+ | ^^^^^^^^^^^^^^^^ missing `Type` in implementation
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0046, E0186, E0201, E0324, E0407, E0795.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/delegation/explicit-paths-pass.rs b/tests/ui/delegation/explicit-paths-pass.rs
new file mode 100644
index 0000000000000..3cacba3f984e2
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths-pass.rs
@@ -0,0 +1,75 @@
+// run-pass
+
+fn foo(x: i32) -> i32 { x * 2 }
+
+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 }
+ reuse foo;
+ fn baz<'a>(&self, x: &'a i32) -> &'a i32 { x }
+}
+
+struct F;
+impl Trait for F {}
+
+mod reuse {
+ pub fn foo(x: i32) -> i32 { x + 1 }
+
+ #[allow(unused, non_camel_case_types)]
+ struct reuse {
+ a: i32,
+ b: i32,
+ c: i32,
+ }
+
+ #[allow(unused)]
+ fn baz() {
+ let (a, b, c) = (0, 0, 0);
+ let val = reuse {a, b, c};
+ assert_eq!(val.a, 0);
+ }
+}
+
+struct S(F);
+impl Trait for S {
+ reuse ::bar { &self.0 }
+ reuse ::description { &self.0 }
+ reuse ::static_method;
+ reuse ::static_method2 { S::static_method(self) }
+ reuse ::baz { &self.0 }
+}
+
+impl S {
+ reuse ::static_method { 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));
+
+ assert_eq!(20, S::foo(10));
+ assert_eq!(30, F::foo(15));
+
+ reuse ::static_method;
+ reuse ::static_method2 { static_method(self) }
+ #[inline]
+ reuse reuse::foo;
+ assert_eq!(42, static_method(42));
+ assert_eq!(21, static_method2(10, 10));
+ assert_eq!(43, foo(42));
+
+ let x: i32 = 15;
+ assert_eq!(&x, s.baz(&x));
+}
diff --git a/tests/ui/delegation/explicit-paths.rs b/tests/ui/delegation/explicit-paths.rs
new file mode 100644
index 0000000000000..efc14213ad27f
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths.rs
@@ -0,0 +1,22 @@
+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..4032f5954cd60
--- /dev/null
+++ b/tests/ui/delegation/explicit-paths.stderr
@@ -0,0 +1,36 @@
+error[E0308]: mismatched types
+ --> $DIR/explicit-paths.rs:11:5
+ |
+LL | reuse ::bar;
+ | ^^^^^^-----------------^
+ | | |
+ | | arguments to this function are incorrect
+ | expected `&F`, found `&S`
+ |
+ = note: expected reference `&F`
+ found reference `&S`
+note: method defined here
+ --> $DIR/explicit-paths.rs:2:8
+ |
+LL | fn bar(&self) -> i32 { 42 }
+ | ^^^ -----
+
+error[E0308]: mismatched types
+ --> $DIR/explicit-paths.rs:18:32
+ |
+LL | reuse ::bar { &self.0 }
+ | ------------------ ^^^^^^^ expected `&S2`, found `&F`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected reference `&S2`
+ found reference `&F`
+note: method defined here
+ --> $DIR/explicit-paths.rs:2:8
+ |
+LL | fn bar(&self) -> i32 { 42 }
+ | ^^^ -----
+
+error: aborting due to 2 previous errors
+
+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..36a6a3c1cbc0a
--- /dev/null
+++ b/tests/ui/delegation/not-supported.rs
@@ -0,0 +1,67 @@
+#![feature(c_variadic)]
+
+mod generics {
+ trait GenericTrait {
+ fn foo(&self, x: T) -> T { x }
+ fn bar() {}
+ }
+ trait Trait {
+ fn foo(&self, x: i32) -> i32 { x }
+ fn bar<'a>(&self, x: &'a i32) -> &'a i32 { x }
+ fn baz(&self, x: T) -> T { x }
+ }
+
+ struct F;
+ impl Trait for F {}
+ impl GenericTrait for F {}
+
+ struct S(F);
+
+ impl GenericTrait for S {
+ reuse ::foo { &self.0 }
+ //~^ ERROR delegation to generic function is not supported yet
+ reuse ::bar;
+ //~^ ERROR delegation to generic function is not supported yet
+ }
+
+ impl Trait for S {
+ reuse ::bar { &self.0 }
+ reuse ::baz { &self.0 }
+ //~^ ERROR delegation to generic function is not supported yet
+ }
+
+ struct GenericS {
+ i32: T
+ }
+
+ impl Trait for GenericS {
+ reuse ::foo { &self.0 }
+ //~^ ERROR delegation to generic function is not supported yet
+ }
+
+ mod to_reuse {
+ pub fn opaque(_: impl super::Trait) -> i32 { 0 }
+ }
+ reuse to_reuse::opaque;
+ //~^ delegation to generic function 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;
+ //~^ delegation to unsafe function is not supported yet
+ reuse to_reuse::extern_fn;
+ //~^ delegation to function with non Rust ABI is not supported yet
+ reuse to_reuse::variadic_fn;
+ //~^ delegation to variadic function is not supported yet
+ reuse to_reuse::const_fn;
+ //~^ delegation to const function 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..4fcee00e169b9
--- /dev/null
+++ b/tests/ui/delegation/not-supported.stderr
@@ -0,0 +1,83 @@
+error: delegation to generic function is not supported yet
+ --> $DIR/not-supported.rs:45:5
+ |
+LL | pub fn opaque(_: impl super::Trait) -> i32 { 0 }
+ | ------------------------------------------ callee defined here
+LL | }
+LL | reuse to_reuse::opaque;
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: delegation to generic function is not supported yet
+ --> $DIR/not-supported.rs:21:9
+ |
+LL | fn foo(&self, x: T) -> T { x }
+ | ------------------------ callee defined here
+...
+LL | reuse ::foo { &self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: delegation to generic function is not supported yet
+ --> $DIR/not-supported.rs:23:9
+ |
+LL | fn bar() {}
+ | -------- callee defined here
+...
+LL | reuse ::bar;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: delegation to generic function is not supported yet
+ --> $DIR/not-supported.rs:29:9
+ |
+LL | fn baz(&self, x: T) -> T { x }
+ | --------------------------- callee defined here
+...
+LL | reuse ::baz { &self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: delegation to generic function is not supported yet
+ --> $DIR/not-supported.rs:38:9
+ |
+LL | fn foo(&self, x: i32) -> i32 { x }
+ | ---------------------------- callee defined here
+...
+LL | reuse ::foo { &self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: delegation to unsafe function is not supported yet
+ --> $DIR/not-supported.rs:57:5
+ |
+LL | pub unsafe fn unsafe_fn() {}
+ | ------------------------- callee defined here
+...
+LL | reuse to_reuse::unsafe_fn;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: delegation to function with non Rust ABI is not supported yet
+ --> $DIR/not-supported.rs:59:5
+ |
+LL | pub extern "C" fn extern_fn() {}
+ | ----------------------------- callee defined here
+...
+LL | reuse to_reuse::extern_fn;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: delegation to variadic function is not supported yet
+ --> $DIR/not-supported.rs:61:5
+ |
+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 function is not supported yet
+ --> $DIR/not-supported.rs:63:5
+ |
+LL | pub const fn const_fn() {}
+ | ----------------------- callee defined here
+...
+LL | reuse to_reuse::const_fn;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/delegation/target-expr-pass.rs b/tests/ui/delegation/target-expr-pass.rs
new file mode 100644
index 0000000000000..6edbc855ca12f
--- /dev/null
+++ b/tests/ui/delegation/target-expr-pass.rs
@@ -0,0 +1,34 @@
+// run-pass
+
+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);
+}