Skip to content

Commit 16d09fa

Browse files
committed
delegation: Support async, const, extern "ABI" and C-variadic functions
Also allow `impl Trait` in delegated functions. The delegation item will refer to the original opaque type from the callee, fresh opaque type won't be created.
1 parent 6312987 commit 16d09fa

File tree

11 files changed

+219
-161
lines changed

11 files changed

+219
-161
lines changed

compiler/rustc_ast_lowering/src/delegation.rs

+75-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,92 @@ impl<'hir> LoweringContext<'_, 'hir> {
123124
})
124125
}
125126

127+
fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) {
128+
if let Some(local_sig_id) = sig_id.as_local() {
129+
// Map may be filled incorrectly due to recursive delegation.
130+
// Error will be emmited later in astconv.
131+
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
132+
Some(sig) => (sig.param_count, sig.c_variadic),
133+
None => (0, false),
134+
}
135+
} else {
136+
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
137+
(sig.inputs().len(), sig.c_variadic)
138+
}
139+
}
140+
126141
fn lower_delegation_decl(
127142
&mut self,
128143
sig_id: DefId,
129-
param_span: Span,
144+
param_count: usize,
145+
c_variadic: bool,
146+
span: Span,
130147
) -> &'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 {
148+
// The last parameter in C variadic functions is skipped in the signature,
149+
// like during regular lowering.
150+
let decl_param_count = param_count - c_variadic as usize;
151+
let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty {
139152
hir_id: self.next_id(),
140153
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
141-
span: self.lower_span(param_span),
154+
span,
142155
}));
143156

144157
let output = self.arena.alloc(hir::Ty {
145158
hir_id: self.next_id(),
146159
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
147-
span: self.lower_span(param_span),
160+
span,
148161
});
149162

150163
self.arena.alloc(hir::FnDecl {
151164
inputs,
152165
output: hir::FnRetTy::Return(output),
153-
c_variadic: false,
166+
c_variadic,
154167
lifetime_elision_allowed: true,
155168
implicit_self: hir::ImplicitSelfKind::None,
156169
})
157170
}
158171

159172
fn lower_delegation_sig(
160173
&mut self,
161-
span: Span,
174+
sig_id: DefId,
162175
decl: &'hir hir::FnDecl<'hir>,
176+
span: Span,
163177
) -> 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-
}
178+
let header = if let Some(local_sig_id) = sig_id.as_local() {
179+
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
180+
Some(sig) => self.lower_fn_header(sig.header),
181+
None => self.generate_header_error(),
182+
}
183+
} else {
184+
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
185+
let asyncness = match self.tcx.asyncness(sig_id) {
186+
Asyncness::Yes => hir::IsAsync::Async(span),
187+
Asyncness::No => hir::IsAsync::NotAsync,
188+
};
189+
hir::FnHeader {
190+
unsafety: sig.unsafety,
191+
constness: self.tcx.constness(sig_id),
192+
asyncness,
193+
abi: sig.abi,
194+
}
195+
};
196+
hir::FnSig { decl, header, span }
174197
}
175198

176-
fn generate_param(&mut self, ty: &'hir hir::Ty<'hir>) -> (hir::Param<'hir>, NodeId) {
199+
fn generate_param(&mut self, span: Span) -> (hir::Param<'hir>, NodeId) {
177200
let pat_node_id = self.next_node_id();
178201
let pat_id = self.lower_node_id(pat_node_id);
179202
let pat = self.arena.alloc(hir::Pat {
180203
hir_id: pat_id,
181204
kind: hir::PatKind::Binding(hir::BindingAnnotation::NONE, pat_id, Ident::empty(), None),
182-
span: ty.span,
205+
span,
183206
default_binding_modes: false,
184207
});
185208

186-
(hir::Param { hir_id: self.next_id(), pat, ty_span: ty.span, span: ty.span }, pat_node_id)
209+
(hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id)
187210
}
188211

189-
fn generate_arg(&mut self, ty: &'hir hir::Ty<'hir>, param_id: HirId) -> hir::Expr<'hir> {
212+
fn generate_arg(&mut self, param_id: HirId, span: Span) -> hir::Expr<'hir> {
190213
let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
191214
ident: Ident::empty(),
192215
hir_id: self.next_id(),
@@ -195,20 +218,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
195218
infer_args: false,
196219
}));
197220

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

201223
hir::Expr {
202224
hir_id: self.next_id(),
203225
kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
204-
span: ty.span,
226+
span,
205227
}
206228
}
207229

208230
fn lower_delegation_body(
209231
&mut self,
210-
decl: &'hir hir::FnDecl<'hir>,
211232
delegation: &Delegation,
233+
param_count: usize,
234+
span: Span,
212235
) -> BodyId {
213236
let path = self.lower_qpath(
214237
delegation.id,
@@ -224,8 +247,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
224247
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
225248
let mut args: Vec<hir::Expr<'hir>> = Vec::new();
226249

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

231254
let arg = if let Some(block) = block
@@ -245,7 +268,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
245268
}
246269
} else {
247270
let pat_hir_id = this.lower_node_id(pat_node_id);
248-
this.generate_arg(param_ty, pat_hir_id)
271+
this.generate_arg(pat_hir_id, span)
249272
};
250273
args.push(arg);
251274
}
@@ -304,14 +327,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
304327
implicit_self: hir::ImplicitSelfKind::None,
305328
});
306329

307-
let sig = self.lower_delegation_sig(span, decl);
330+
let header = self.generate_header_error();
331+
let sig = hir::FnSig { decl, header, span };
332+
308333
let body_id = self.lower_body(|this| {
309334
let expr =
310335
hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span };
311336
(&[], expr)
312337
});
313338
DelegationResults { generics, body_id, sig }
314339
}
340+
341+
fn generate_header_error(&self) -> hir::FnHeader {
342+
hir::FnHeader {
343+
unsafety: hir::Unsafety::Normal,
344+
constness: hir::Constness::NotConst,
345+
asyncness: hir::IsAsync::NotAsync,
346+
abi: abi::Abi::Rust,
347+
}
348+
}
315349
}
316350

317351
struct SelfResolver<'a> {

compiler/rustc_ast_lowering/src/item.rs

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

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

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

-28
Original file line numberDiff line numberDiff line change
@@ -2196,11 +2196,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
21962196
try_emit("recursive delegation");
21972197
}
21982198

2199-
let sig = self.tcx().fn_sig(sig_id).instantiate_identity();
2200-
if sig.output().has_opaque_types() {
2201-
try_emit("delegation to a function with opaque type");
2202-
}
2203-
22042199
let sig_generics = self.tcx().generics_of(sig_id);
22052200
let parent = self.tcx().parent(self.item_def_id());
22062201
let parent_generics = self.tcx().generics_of(parent);
@@ -2212,29 +2207,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22122207
try_emit("delegation with early bound generics");
22132208
}
22142209

2215-
if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes {
2216-
try_emit("delegation to async functions");
2217-
}
2218-
2219-
if self.tcx().constness(sig_id) == hir::Constness::Const {
2220-
try_emit("delegation to const functions");
2221-
}
2222-
2223-
if sig.c_variadic() {
2224-
try_emit("delegation to variadic functions");
2225-
// variadic functions are also `unsafe` and `extern "C"`.
2226-
// Do not emit same error multiple times.
2227-
return error_occured;
2228-
}
2229-
2230-
if let hir::Unsafety::Unsafe = sig.unsafety() {
2231-
try_emit("delegation to unsafe functions");
2232-
}
2233-
2234-
if abi::Abi::Rust != sig.abi() {
2235-
try_emit("delegation to non Rust ABI functions");
2236-
}
2237-
22382210
error_occured
22392211
}
22402212

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_resolve/src/late.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par
2424
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
2525
use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate};
2626
use rustc_middle::middle::resolve_bound_vars::Set1;
27+
use rustc_middle::ty::DelegationFnSig;
2728
use rustc_middle::{bug, span_bug};
2829
use rustc_session::config::{CrateType, ResolveDocLinks};
2930
use rustc_session::lint;
@@ -4712,12 +4713,13 @@ struct ItemInfoCollector<'a, 'b, 'tcx> {
47124713

47134714
impl ItemInfoCollector<'_, '_, '_> {
47144715
fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId) {
4715-
let def_id = self.r.local_def_id(id);
4716-
self.r.fn_parameter_counts.insert(def_id, sig.decl.inputs.len());
4717-
4718-
if sig.decl.has_self() {
4719-
self.r.has_self.insert(def_id);
4720-
}
4716+
let sig = DelegationFnSig {
4717+
header: sig.header,
4718+
param_count: sig.decl.inputs.len(),
4719+
has_self: sig.decl.has_self(),
4720+
c_variadic: sig.decl.c_variadic(),
4721+
};
4722+
self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig);
47214723
}
47224724
}
47234725

compiler/rustc_resolve/src/late/diagnostics.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -2039,7 +2039,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
20392039
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called },
20402040
ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType,
20412041
ast::AssocItemKind::Delegation(..)
2042-
if self.r.has_self.contains(&self.r.local_def_id(assoc_item.id)) =>
2042+
if self.r.delegation_fn_sigs[&self.r.local_def_id(assoc_item.id)]
2043+
.has_self =>
20432044
{
20442045
AssocSuggestion::MethodWithSelf { called }
20452046
}
@@ -2062,7 +2063,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
20622063
if filter_fn(res) {
20632064
let def_id = res.def_id();
20642065
let has_self = match def_id.as_local() {
2065-
Some(def_id) => self.r.has_self.contains(&def_id),
2066+
Some(def_id) => {
2067+
self.r.delegation_fn_sigs.get(&def_id).map_or(false, |sig| sig.has_self)
2068+
}
20662069
None => self
20672070
.r
20682071
.tcx

0 commit comments

Comments
 (0)