Skip to content

Commit 5557f8c

Browse files
committed
Auto merge of #122500 - petrochenkov:deleg, r=fmease
delegation: Support renaming, and async, const, extern "ABI" and C-variadic functions Also allow delegating to functions with opaque types (`impl Trait`). The delegation item will refer to the original opaque type from the callee, fresh opaque type won't be created, which seems like a reasonable behavior. (Such delegation items will cause query cycles when used in trait impls, but it can be fixed later.) Part of #118212.
2 parents e936289 + 7b7c26f commit 5557f8c

File tree

17 files changed

+282
-160
lines changed

17 files changed

+282
-160
lines changed

compiler/rustc_ast/src/ast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3112,6 +3112,7 @@ pub struct Delegation {
31123112
/// Path resolution id.
31133113
pub id: NodeId,
31143114
pub qself: Option<P<QSelf>>,
3115+
pub rename: Option<Ident>,
31153116
pub path: Path,
31163117
pub body: Option<P<Block>>,
31173118
}

compiler/rustc_ast/src/mut_visit.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1149,10 +1149,13 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
11491149
}
11501150
ItemKind::MacCall(m) => vis.visit_mac_call(m),
11511151
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
1152-
ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
1152+
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
11531153
vis.visit_id(id);
11541154
vis.visit_qself(qself);
11551155
vis.visit_path(path);
1156+
if let Some(rename) = rename {
1157+
vis.visit_ident(rename);
1158+
}
11561159
if let Some(body) = body {
11571160
vis.visit_block(body);
11581161
}
@@ -1195,10 +1198,13 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
11951198
visit_opt(ty, |ty| visitor.visit_ty(ty));
11961199
}
11971200
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
1198-
AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
1201+
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
11991202
visitor.visit_id(id);
12001203
visitor.visit_qself(qself);
12011204
visitor.visit_path(path);
1205+
if let Some(rename) = rename {
1206+
visitor.visit_ident(rename);
1207+
}
12021208
if let Some(body) = body {
12031209
visitor.visit_block(body);
12041210
}

compiler/rustc_ast/src/visit.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -382,11 +382,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) -> V::Resu
382382
}
383383
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
384384
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
385-
ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
385+
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
386386
if let Some(qself) = qself {
387387
try_visit!(visitor.visit_ty(&qself.ty));
388388
}
389389
try_visit!(visitor.visit_path(path, *id));
390+
visit_opt!(visitor, visit_ident, *rename);
390391
visit_opt!(visitor, visit_block, body);
391392
}
392393
}
@@ -782,11 +783,12 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(
782783
AssocItemKind::MacCall(mac) => {
783784
try_visit!(visitor.visit_mac_call(mac));
784785
}
785-
AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
786+
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
786787
if let Some(qself) = qself {
787788
try_visit!(visitor.visit_ty(&qself.ty));
788789
}
789790
try_visit!(visitor.visit_path(path, *id));
791+
visit_opt!(visitor, visit_ident, *rename);
790792
visit_opt!(visitor, visit_block, body);
791793
}
792794
}

compiler/rustc_ast_lowering/src/delegation.rs

+76-41
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ use rustc_errors::ErrorGuaranteed;
4949
use rustc_hir as hir;
5050
use rustc_hir::def_id::DefId;
5151
use rustc_middle::span_bug;
52-
use rustc_middle::ty::ResolverAstLowering;
52+
use rustc_middle::ty::{Asyncness, ResolverAstLowering};
5353
use rustc_span::{symbol::Ident, Span};
5454
use rustc_target::spec::abi;
5555
use std::iter;
@@ -67,7 +67,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
6767
return false;
6868
};
6969
if let Some(local_sig_id) = sig_id.as_local() {
70-
self.resolver.has_self.contains(&local_sig_id)
70+
self.resolver.delegation_fn_sigs[&local_sig_id].has_self
7171
} else {
7272
match self.tcx.def_kind(sig_id) {
7373
DefKind::Fn => false,
@@ -82,13 +82,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
8282
delegation: &Delegation,
8383
item_id: NodeId,
8484
) -> DelegationResults<'hir> {
85-
let span = delegation.path.segments.last().unwrap().ident.span;
85+
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
8686
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span);
8787
match sig_id {
8888
Ok(sig_id) => {
89-
let decl = self.lower_delegation_decl(sig_id, span);
90-
let sig = self.lower_delegation_sig(span, decl);
91-
let body_id = self.lower_delegation_body(sig.decl, delegation);
89+
let (param_count, c_variadic) = self.param_count(sig_id);
90+
let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span);
91+
let sig = self.lower_delegation_sig(sig_id, decl, span);
92+
let body_id = self.lower_delegation_body(delegation, param_count, span);
9293

9394
let generics = self.lower_delegation_generics(span);
9495
DelegationResults { body_id, sig, generics }
@@ -123,70 +124,93 @@ impl<'hir> LoweringContext<'_, 'hir> {
123124
})
124125
}
125126

127+
// Function parameter count, including C variadic `...` if present.
128+
fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) {
129+
if let Some(local_sig_id) = sig_id.as_local() {
130+
// Map may be filled incorrectly due to recursive delegation.
131+
// Error will be emmited later during HIR ty lowering.
132+
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
133+
Some(sig) => (sig.param_count, sig.c_variadic),
134+
None => (0, false),
135+
}
136+
} else {
137+
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
138+
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
139+
}
140+
}
141+
126142
fn lower_delegation_decl(
127143
&mut self,
128144
sig_id: DefId,
129-
param_span: Span,
145+
param_count: usize,
146+
c_variadic: bool,
147+
span: Span,
130148
) -> &'hir hir::FnDecl<'hir> {
131-
let args_count = if let Some(local_sig_id) = sig_id.as_local() {
132-
// Map may be filled incorrectly due to recursive delegation.
133-
// Error will be emitted later during HIR ty lowering.
134-
self.resolver.fn_parameter_counts.get(&local_sig_id).cloned().unwrap_or_default()
135-
} else {
136-
self.tcx.fn_arg_names(sig_id).len()
137-
};
138-
let inputs = self.arena.alloc_from_iter((0..args_count).map(|arg| hir::Ty {
149+
// The last parameter in C variadic functions is skipped in the signature,
150+
// like during regular lowering.
151+
let decl_param_count = param_count - c_variadic as usize;
152+
let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty {
139153
hir_id: self.next_id(),
140154
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
141-
span: self.lower_span(param_span),
155+
span,
142156
}));
143157

144158
let output = self.arena.alloc(hir::Ty {
145159
hir_id: self.next_id(),
146160
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
147-
span: self.lower_span(param_span),
161+
span,
148162
});
149163

150164
self.arena.alloc(hir::FnDecl {
151165
inputs,
152166
output: hir::FnRetTy::Return(output),
153-
c_variadic: false,
167+
c_variadic,
154168
lifetime_elision_allowed: true,
155169
implicit_self: hir::ImplicitSelfKind::None,
156170
})
157171
}
158172

159173
fn lower_delegation_sig(
160174
&mut self,
161-
span: Span,
175+
sig_id: DefId,
162176
decl: &'hir hir::FnDecl<'hir>,
177+
span: Span,
163178
) -> hir::FnSig<'hir> {
164-
hir::FnSig {
165-
decl,
166-
header: hir::FnHeader {
167-
unsafety: hir::Unsafety::Normal,
168-
constness: hir::Constness::NotConst,
169-
asyncness: hir::IsAsync::NotAsync,
170-
abi: abi::Abi::Rust,
171-
},
172-
span: self.lower_span(span),
173-
}
179+
let header = if let Some(local_sig_id) = sig_id.as_local() {
180+
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
181+
Some(sig) => self.lower_fn_header(sig.header),
182+
None => self.generate_header_error(),
183+
}
184+
} else {
185+
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
186+
let asyncness = match self.tcx.asyncness(sig_id) {
187+
Asyncness::Yes => hir::IsAsync::Async(span),
188+
Asyncness::No => hir::IsAsync::NotAsync,
189+
};
190+
hir::FnHeader {
191+
unsafety: sig.unsafety,
192+
constness: self.tcx.constness(sig_id),
193+
asyncness,
194+
abi: sig.abi,
195+
}
196+
};
197+
hir::FnSig { decl, header, span }
174198
}
175199

176-
fn generate_param(&mut self, ty: &'hir hir::Ty<'hir>) -> (hir::Param<'hir>, NodeId) {
200+
fn generate_param(&mut self, span: Span) -> (hir::Param<'hir>, NodeId) {
177201
let pat_node_id = self.next_node_id();
178202
let pat_id = self.lower_node_id(pat_node_id);
179203
let pat = self.arena.alloc(hir::Pat {
180204
hir_id: pat_id,
181205
kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, Ident::empty(), None),
182-
span: ty.span,
206+
span,
183207
default_binding_modes: false,
184208
});
185209

186-
(hir::Param { hir_id: self.next_id(), pat, ty_span: ty.span, span: ty.span }, pat_node_id)
210+
(hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id)
187211
}
188212

189-
fn generate_arg(&mut self, ty: &'hir hir::Ty<'hir>, param_id: HirId) -> hir::Expr<'hir> {
213+
fn generate_arg(&mut self, param_id: HirId, span: Span) -> hir::Expr<'hir> {
190214
let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
191215
ident: Ident::empty(),
192216
hir_id: self.next_id(),
@@ -195,20 +219,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
195219
infer_args: false,
196220
}));
197221

198-
let path =
199-
self.arena.alloc(hir::Path { span: ty.span, res: Res::Local(param_id), segments });
222+
let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments });
200223

201224
hir::Expr {
202225
hir_id: self.next_id(),
203226
kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
204-
span: ty.span,
227+
span,
205228
}
206229
}
207230

208231
fn lower_delegation_body(
209232
&mut self,
210-
decl: &'hir hir::FnDecl<'hir>,
211233
delegation: &Delegation,
234+
param_count: usize,
235+
span: Span,
212236
) -> BodyId {
213237
let path = self.lower_qpath(
214238
delegation.id,
@@ -224,8 +248,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
224248
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
225249
let mut args: Vec<hir::Expr<'hir>> = Vec::new();
226250

227-
for (idx, param_ty) in decl.inputs.iter().enumerate() {
228-
let (param, pat_node_id) = this.generate_param(param_ty);
251+
for idx in 0..param_count {
252+
let (param, pat_node_id) = this.generate_param(span);
229253
parameters.push(param);
230254

231255
let arg = if let Some(block) = block
@@ -245,7 +269,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
245269
}
246270
} else {
247271
let pat_hir_id = this.lower_node_id(pat_node_id);
248-
this.generate_arg(param_ty, pat_hir_id)
272+
this.generate_arg(pat_hir_id, span)
249273
};
250274
args.push(arg);
251275
}
@@ -304,14 +328,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
304328
implicit_self: hir::ImplicitSelfKind::None,
305329
});
306330

307-
let sig = self.lower_delegation_sig(span, decl);
331+
let header = self.generate_header_error();
332+
let sig = hir::FnSig { decl, header, span };
333+
308334
let body_id = self.lower_body(|this| {
309335
let expr =
310336
hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span };
311337
(&[], expr)
312338
});
313339
DelegationResults { generics, body_id, sig }
314340
}
341+
342+
fn generate_header_error(&self) -> hir::FnHeader {
343+
hir::FnHeader {
344+
unsafety: hir::Unsafety::Normal,
345+
constness: hir::Constness::NotConst,
346+
asyncness: hir::IsAsync::NotAsync,
347+
abi: abi::Abi::Rust,
348+
}
349+
}
315350
}
316351

317352
struct SelfResolver<'a> {

compiler/rustc_ast_lowering/src/item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
13441344
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
13451345
}
13461346

1347-
fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
1347+
pub(super) fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
13481348
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
13491349
hir::IsAsync::Async(span)
13501350
} else {

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

-28
Original file line numberDiff line numberDiff line change
@@ -1964,11 +1964,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
19641964
try_emit("recursive delegation");
19651965
}
19661966

1967-
let sig = self.tcx().fn_sig(sig_id).instantiate_identity();
1968-
if sig.output().has_opaque_types() {
1969-
try_emit("delegation to a function with opaque type");
1970-
}
1971-
19721967
let sig_generics = self.tcx().generics_of(sig_id);
19731968
let parent = self.tcx().parent(self.item_def_id());
19741969
let parent_generics = self.tcx().generics_of(parent);
@@ -1991,29 +1986,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
19911986
try_emit("delegation to a trait method from a free function");
19921987
}
19931988

1994-
if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes {
1995-
try_emit("delegation to async functions");
1996-
}
1997-
1998-
if self.tcx().constness(sig_id) == hir::Constness::Const {
1999-
try_emit("delegation to const functions");
2000-
}
2001-
2002-
if sig.c_variadic() {
2003-
try_emit("delegation to variadic functions");
2004-
// variadic functions are also `unsafe` and `extern "C"`.
2005-
// Do not emit same error multiple times.
2006-
return error_occured;
2007-
}
2008-
2009-
if let hir::Unsafety::Unsafe = sig.unsafety() {
2010-
try_emit("delegation to unsafe functions");
2011-
}
2012-
2013-
if abi::Abi::Rust != sig.abi() {
2014-
try_emit("delegation to non Rust ABI functions");
2015-
}
2016-
20171989
error_occured
20181990
}
20191991

compiler/rustc_middle/src/ty/mod.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use rustc_data_structures::unord::UnordMap;
4545
use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
4646
use rustc_hir as hir;
4747
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
48-
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet};
48+
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
4949
use rustc_index::IndexVec;
5050
use rustc_macros::HashStable;
5151
use rustc_query_system::ich::StableHashingContext;
@@ -224,8 +224,15 @@ pub struct ResolverAstLowering {
224224
pub lint_buffer: Steal<LintBuffer>,
225225

226226
/// Information about functions signatures for delegation items expansion
227-
pub has_self: LocalDefIdSet,
228-
pub fn_parameter_counts: LocalDefIdMap<usize>,
227+
pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
228+
}
229+
230+
#[derive(Debug)]
231+
pub struct DelegationFnSig {
232+
pub header: ast::FnHeader,
233+
pub param_count: usize,
234+
pub has_self: bool,
235+
pub c_variadic: bool,
229236
}
230237

231238
#[derive(Clone, Copy, Debug)]

compiler/rustc_parse/src/parser/item.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,8 @@ impl<'a> Parser<'a> {
686686
(None, self.parse_path(PathStyle::Expr)?)
687687
};
688688

689+
let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None };
690+
689691
let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
690692
Some(self.parse_block()?)
691693
} else {
@@ -695,11 +697,9 @@ impl<'a> Parser<'a> {
695697
let span = span.to(self.prev_token.span);
696698
self.psess.gated_spans.gate(sym::fn_delegation, span);
697699

698-
let ident = path.segments.last().map(|seg| seg.ident).unwrap_or(Ident::empty());
699-
Ok((
700-
ident,
701-
ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, body })),
702-
))
700+
let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
701+
let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body };
702+
Ok((ident, ItemKind::Delegation(Box::new(deleg))))
703703
}
704704

705705
fn parse_item_list<T>(

0 commit comments

Comments
 (0)