1use std::iter;
40
41use ast::visit::Visitor;
42use hir::def::{DefKind, Res};
43use hir::{BodyId, HirId};
44use rustc_abi::ExternAbi;
45use rustc_ast as ast;
46use rustc_ast::*;
47use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
48use rustc_hir::attrs::{AttributeKind, InlineAttr};
49use rustc_hir::def_id::{DefId, LocalDefId};
50use rustc_hir::{self as hir, FnDeclFlags};
51use rustc_middle::span_bug;
52use rustc_middle::ty::{Asyncness, TyCtxt};
53use rustc_span::symbol::kw;
54use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
55
56use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
57use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee};
58use crate::{
59 AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
60 ResolverAstLoweringExt, index_crate,
61};
62
63mod generics;
64
65pub(crate) struct DelegationResults<'hir> {
66 pub body_id: hir::BodyId,
67 pub sig: hir::FnSig<'hir>,
68 pub ident: Ident,
69 pub generics: &'hir hir::Generics<'hir>,
70}
71
72struct AttrAdditionInfo {
73 pub equals: fn(&hir::Attribute) -> bool,
74 pub kind: AttrAdditionKind,
75}
76
77enum AttrAdditionKind {
78 Default { factory: fn(Span) -> hir::Attribute },
79 Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute },
80}
81
82const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
83
84static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[
85 AttrAdditionInfo {
86 equals: |a| #[allow(non_exhaustive_omitted_patterns)] match a {
hir::Attribute::Parsed(AttributeKind::MustUse { .. }) => true,
_ => false,
}matches!(a, hir::Attribute::Parsed(AttributeKind::MustUse { .. })),
87 kind: AttrAdditionKind::Inherit {
88 factory: |span, original_attr| {
89 let reason = match original_attr {
90 hir::Attribute::Parsed(AttributeKind::MustUse { reason, .. }) => *reason,
91 _ => None,
92 };
93
94 hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
95 },
96 },
97 },
98 AttrAdditionInfo {
99 equals: |a| #[allow(non_exhaustive_omitted_patterns)] match a {
hir::Attribute::Parsed(AttributeKind::Inline(..)) => true,
_ => false,
}matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))),
100 kind: AttrAdditionKind::Default {
101 factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)),
102 },
103 },
104];
105
106pub(crate) fn delegations_resolutions(
107 tcx: TyCtxt<'_>,
108 _: (),
109) -> FxIndexMap<LocalDefId, Result<DefId, ErrorGuaranteed>> {
110 let krate = tcx.hir_crate(());
111
112 let (resolver, ast_crate) = &*krate.delayed_resolver.borrow();
113
114 let ast_index = index_crate(resolver, ast_crate);
117
118 let mut result = FxIndexMap::<LocalDefId, Result<DefId, ErrorGuaranteed>>::default();
119
120 for &def_id in &krate.delayed_ids {
121 let delegation = ast_index[def_id].delegation().expect("processing delegations");
122 let span = delegation.last_segment_span();
123
124 if let Some(info) = resolver.delegation_info(def_id) {
125 let res = info.resolution_id.map(|id| check_for_cycles(tcx, id, span).map(|_| id));
126 result.insert(def_id, res.flatten());
127 } else {
128 tcx.dcx().span_delayed_bug(
129 span,
130 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("delegation resolution record was not found for {0:?}",
def_id))
})format!("delegation resolution record was not found for {def_id:?}"),
131 );
132 }
133 }
134
135 result
136}
137
138fn check_for_cycles(tcx: TyCtxt<'_>, mut def_id: DefId, span: Span) -> Result<(), ErrorGuaranteed> {
139 let mut visited: FxHashSet<DefId> = Default::default();
140
141 let (resolver, _) = &*tcx.hir_crate(()).delayed_resolver.borrow();
142
143 loop {
144 visited.insert(def_id);
145
146 if let Some(local_id) = def_id.as_local()
150 && let Some(info) = resolver.delegation_info(local_id)
151 && let Ok(id) = info.resolution_id
152 {
153 def_id = id;
154 if visited.contains(&def_id) {
155 return Err(match visited.len() {
156 1 => tcx.dcx().emit_err(UnresolvedDelegationCallee { span }),
157 _ => tcx.dcx().emit_err(CycleInDelegationSignatureResolution { span }),
158 });
159 }
160 } else {
161 return Ok(());
162 }
163 }
164}
165
166impl<'hir> LoweringContext<'_, 'hir> {
167 fn is_method(&self, def_id: DefId, span: Span) -> bool {
168 match self.tcx.def_kind(def_id) {
169 DefKind::Fn => false,
170 DefKind::AssocFn => self.tcx.associated_item(def_id).is_method(),
171 _ => ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("unexpected DefKind for delegation item"))span_bug!(span, "unexpected DefKind for delegation item"),
172 }
173 }
174
175 pub(crate) fn lower_delegation(
176 &mut self,
177 delegation: &Delegation,
178 item_id: NodeId,
179 ) -> DelegationResults<'hir> {
180 let span = self.lower_span(delegation.last_segment_span());
181
182 let sig_id = self.tcx.delegations_resolutions(()).get(&self.owner.def_id).copied();
183
184 let Some(Ok(sig_id)) = sig_id else {
187 self.dcx().span_delayed_bug(
188 span,
189 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("LoweringContext: the delegation {0:?} is unresolved",
item_id))
})format!("LoweringContext: the delegation {:?} is unresolved", item_id),
190 );
191
192 return self.generate_delegation_error(span, delegation);
193 };
194
195 self.add_attrs_if_needed(span, sig_id);
196
197 let is_method = self.is_method(sig_id, span);
198
199 let (param_count, c_variadic) = self.param_count(sig_id);
200
201 let mut generics = self.uplift_delegation_generics(delegation, sig_id, is_method);
202
203 let (body_id, call_expr_id) =
204 self.lower_delegation_body(delegation, is_method, param_count, &mut generics, span);
205
206 let decl = self.lower_delegation_decl(
207 sig_id,
208 param_count,
209 c_variadic,
210 span,
211 &generics,
212 delegation.id,
213 call_expr_id,
214 );
215
216 let sig = self.lower_delegation_sig(sig_id, decl, span);
217 let ident = self.lower_ident(delegation.ident);
218
219 let generics = self.arena.alloc(hir::Generics {
220 has_where_clause_predicates: false,
221 params: self.arena.alloc_from_iter(generics.all_params()),
222 predicates: self.arena.alloc_from_iter(generics.all_predicates()),
223 span,
224 where_clause_span: span,
225 });
226
227 DelegationResults { body_id, sig, ident, generics }
228 }
229
230 fn add_attrs_if_needed(&mut self, span: Span, sig_id: DefId) {
231 let new_attrs =
232 self.create_new_attrs(ATTRS_ADDITIONS, span, sig_id, self.attrs.get(&PARENT_ID));
233
234 if new_attrs.is_empty() {
235 return;
236 }
237
238 let new_arena_allocated_attrs = match self.attrs.get(&PARENT_ID) {
239 Some(existing_attrs) => self.arena.alloc_from_iter(
240 existing_attrs.iter().map(|a| a.clone()).chain(new_attrs.into_iter()),
241 ),
242 None => self.arena.alloc_from_iter(new_attrs.into_iter()),
243 };
244
245 self.attrs.insert(PARENT_ID, new_arena_allocated_attrs);
246 }
247
248 fn create_new_attrs(
249 &self,
250 candidate_additions: &[AttrAdditionInfo],
251 span: Span,
252 sig_id: DefId,
253 existing_attrs: Option<&&[hir::Attribute]>,
254 ) -> Vec<hir::Attribute> {
255 candidate_additions
256 .iter()
257 .filter_map(|addition_info| {
258 if let Some(existing_attrs) = existing_attrs
259 && existing_attrs
260 .iter()
261 .any(|existing_attr| (addition_info.equals)(existing_attr))
262 {
263 return None;
264 }
265
266 match addition_info.kind {
267 AttrAdditionKind::Default { factory } => Some(factory(span)),
268 AttrAdditionKind::Inherit { factory, .. } =>
269 {
270 #[allow(deprecated)]
271 self.tcx
272 .get_all_attrs(sig_id)
273 .iter()
274 .find_map(|a| (addition_info.equals)(a).then(|| factory(span, a)))
275 }
276 }
277 })
278 .collect::<Vec<_>>()
279 }
280
281 fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
282 self.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
283 }
284
285 fn param_count(&self, def_id: DefId) -> (usize, bool ) {
287 let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
288 (sig.inputs().len() + usize::from(sig.c_variadic()), sig.c_variadic())
289 }
290
291 fn lower_delegation_decl(
292 &mut self,
293 sig_id: DefId,
294 param_count: usize,
295 c_variadic: bool,
296 span: Span,
297 generics: &GenericsGenerationResults<'hir>,
298 call_path_node_id: NodeId,
299 call_expr_id: HirId,
300 ) -> &'hir hir::FnDecl<'hir> {
301 let decl_param_count = param_count - c_variadic as usize;
304 let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty {
305 hir_id: self.next_id(),
306 kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig(
307 sig_id,
308 hir::InferDelegationSig::Input(arg),
309 )),
310 span,
311 }));
312
313 let output = self.arena.alloc(hir::Ty {
314 hir_id: self.next_id(),
315 kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig(
316 sig_id,
317 hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationInfo {
318 call_expr_id,
319 call_path_res: self.get_resolution_id(call_path_node_id),
320 child_args_segment_id: generics.child.args_segment_id,
321 parent_args_segment_id: generics.parent.args_segment_id,
322 self_ty_id: generics.self_ty_id,
323 propagate_self_ty: generics.propagate_self_ty,
324 })),
325 )),
326 span,
327 });
328
329 self.arena.alloc(hir::FnDecl {
330 inputs,
331 output: hir::FnRetTy::Return(output),
332 fn_decl_kind: FnDeclFlags::default()
333 .set_lifetime_elision_allowed(true)
334 .set_c_variadic(c_variadic),
335 })
336 }
337
338 fn lower_delegation_sig(
339 &mut self,
340 sig_id: DefId,
341 decl: &'hir hir::FnDecl<'hir>,
342 span: Span,
343 ) -> hir::FnSig<'hir> {
344 let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
345 let asyncness = match self.tcx.asyncness(sig_id) {
346 Asyncness::Yes => hir::IsAsync::Async(span),
347 Asyncness::No => hir::IsAsync::NotAsync,
348 };
349
350 let header = hir::FnHeader {
351 safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
352 hir::HeaderSafety::SafeTargetFeatures
353 } else {
354 hir::HeaderSafety::Normal(sig.safety())
355 },
356 constness: self.tcx.constness(sig_id),
357 asyncness,
358 abi: sig.abi(),
359 };
360
361 hir::FnSig { decl, header, span }
362 }
363
364 fn generate_param(
365 &mut self,
366 is_method: bool,
367 idx: usize,
368 span: Span,
369 ) -> (hir::Param<'hir>, NodeId) {
370 let pat_node_id = self.next_node_id();
371 let pat_id = self.lower_node_id(pat_node_id);
372 let name = if is_method && idx == 0 {
374 kw::SelfLower
375 } else {
376 Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("arg{0}", idx))
})format!("arg{idx}"))
377 };
378 let ident = Ident::with_dummy_span(name);
379 let pat = self.arena.alloc(hir::Pat {
380 hir_id: pat_id,
381 kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, ident, None),
382 span,
383 default_binding_modes: false,
384 });
385
386 (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id)
387 }
388
389 fn generate_arg(
390 &mut self,
391 is_method: bool,
392 idx: usize,
393 param_id: HirId,
394 span: Span,
395 ) -> hir::Expr<'hir> {
396 let name = if is_method && idx == 0 {
398 kw::SelfLower
399 } else {
400 Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("arg{0}", idx))
})format!("arg{idx}"))
401 };
402
403 let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
404 ident: Ident::with_dummy_span(name),
405 hir_id: self.next_id(),
406 res: Res::Local(param_id),
407 args: None,
408 infer_args: false,
409 }));
410
411 let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments });
412 self.mk_expr(hir::ExprKind::Path(hir::QPath::Resolved(None, path)), span)
413 }
414
415 fn lower_delegation_body(
416 &mut self,
417 delegation: &Delegation,
418 is_method: bool,
419 param_count: usize,
420 generics: &mut GenericsGenerationResults<'hir>,
421 span: Span,
422 ) -> (BodyId, HirId) {
423 let block = delegation.body.as_deref();
424 let mut call_expr_id = HirId::INVALID;
425
426 let block_id = self.lower_body(|this| {
427 let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count);
428 let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);
429 let mut stmts: &[hir::Stmt<'hir>] = &[];
430
431 for idx in 0..param_count {
432 let (param, pat_node_id) = this.generate_param(is_method, idx, span);
433 parameters.push(param);
434
435 let generate_arg =
436 |this: &mut Self| this.generate_arg(is_method, idx, param.pat.hir_id, span);
437
438 let arg = if let Some(block) = block
439 && idx == 0
440 {
441 let mut self_resolver = SelfResolver {
442 ctxt: this,
443 path_id: delegation.id,
444 self_param_id: pat_node_id,
445 };
446 self_resolver.visit_block(block);
447 this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);
449
450 let block = this.lower_block_noalloc(HirId::INVALID, block, false);
454
455 stmts = block.stmts;
456
457 if let Some(&expr) = block.expr { expr } else { generate_arg(this) }
463 } else {
464 generate_arg(this)
465 };
466
467 args.push(arg);
468 }
469
470 if param_count == 0
476 && let Some(block) = block
477 {
478 args.push(this.lower_block_expr(&block));
479 }
480
481 let (final_expr, hir_id) =
482 this.finalize_body_lowering(delegation, stmts, args, generics, span);
483
484 call_expr_id = hir_id;
485
486 (this.arena.alloc_from_iter(parameters), final_expr)
487 });
488
489 if true {
match (&call_expr_id, &HirId::INVALID) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_ne!(call_expr_id, HirId::INVALID);
490
491 (block_id, call_expr_id)
492 }
493
494 fn finalize_body_lowering(
495 &mut self,
496 delegation: &Delegation,
497 stmts: &'hir [hir::Stmt<'hir>],
498 args: Vec<hir::Expr<'hir>>,
499 generics: &mut GenericsGenerationResults<'hir>,
500 span: Span,
501 ) -> (hir::Expr<'hir>, HirId) {
502 let path = self.lower_qpath(
503 delegation.id,
504 &delegation.qself,
505 &delegation.path,
506 ParamMode::Optional,
507 AllowReturnTypeNotation::No,
508 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
509 None,
510 );
511
512 let new_path = match path {
513 hir::QPath::Resolved(ty, path) => {
514 let mut new_path = path.clone();
515 let len = new_path.segments.len();
516
517 new_path.segments = self.arena.alloc_from_iter(
518 new_path.segments.iter().enumerate().map(|(idx, segment)| {
519 if idx + 2 == len {
520 self.process_segment(span, segment, &mut generics.parent)
521 } else if idx + 1 == len {
522 self.process_segment(span, segment, &mut generics.child)
523 } else {
524 segment.clone()
525 }
526 }),
527 );
528
529 hir::QPath::Resolved(ty, self.arena.alloc(new_path))
530 }
531 hir::QPath::TypeRelative(ty, segment) => {
532 let segment = self.process_segment(span, segment, &mut generics.child);
533
534 hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
535 }
536 };
537
538 generics.self_ty_id = match new_path {
539 hir::QPath::Resolved(ty, _) => ty,
540 hir::QPath::TypeRelative(ty, _) => Some(ty),
541 }
542 .map(|ty| ty.hir_id);
543
544 let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span));
545 let args = self.arena.alloc_from_iter(args);
546 let call = self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span));
547
548 let block = self.arena.alloc(hir::Block {
549 stmts,
550 expr: Some(call),
551 hir_id: self.next_id(),
552 rules: hir::BlockCheckMode::DefaultBlock,
553 span,
554 targeted_by_break: false,
555 });
556
557 (self.mk_expr(hir::ExprKind::Block(block, None), span), call.hir_id)
558 }
559
560 fn process_segment(
561 &mut self,
562 span: Span,
563 segment: &hir::PathSegment<'hir>,
564 result: &mut GenericsGenerationResult<'hir>,
565 ) -> hir::PathSegment<'hir> {
566 let details = result.generics.args_propagation_details();
567
568 let generics = result.generics.into_hir_generics(self, span);
571 let segment = if details.should_propagate {
572 let args = generics.into_generic_args(self, span);
573
574 let args = if args.is_empty() { None } else { Some(args) };
576
577 hir::PathSegment { args, ..segment.clone() }
578 } else {
579 segment.clone()
580 };
581
582 if details.use_args_in_sig_inheritance {
583 result.args_segment_id = Some(segment.hir_id);
584 }
585
586 segment
587 }
588
589 fn generate_delegation_error(
590 &mut self,
591 span: Span,
592 delegation: &Delegation,
593 ) -> DelegationResults<'hir> {
594 let decl = self.arena.alloc(hir::FnDecl::dummy(span));
595
596 let header = self.generate_header_error();
597 let sig = hir::FnSig { decl, header, span };
598
599 let ident = self.lower_ident(delegation.ident);
600
601 let body_id = self.lower_body(|this| {
602 let path = this.lower_qpath(
603 delegation.id,
604 &delegation.qself,
605 &delegation.path,
606 ParamMode::Optional,
607 AllowReturnTypeNotation::No,
608 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
609 None,
610 );
611
612 let callee_path = this.arena.alloc(this.mk_expr(hir::ExprKind::Path(path), span));
613 let args = if let Some(block) = delegation.body.as_ref() {
614 this.arena.alloc_slice(&[this.lower_block_expr(block)])
615 } else {
616 &mut []
617 };
618
619 let call = this.arena.alloc(this.mk_expr(hir::ExprKind::Call(callee_path, args), span));
620
621 let block = this.arena.alloc(hir::Block {
622 stmts: &[],
623 expr: Some(call),
624 hir_id: this.next_id(),
625 rules: hir::BlockCheckMode::DefaultBlock,
626 span,
627 targeted_by_break: false,
628 });
629
630 (&[], this.mk_expr(hir::ExprKind::Block(block, None), span))
631 });
632
633 let generics = hir::Generics::empty();
634 DelegationResults { ident, generics, body_id, sig }
635 }
636
637 fn generate_header_error(&self) -> hir::FnHeader {
638 hir::FnHeader {
639 safety: hir::Safety::Safe.into(),
640 constness: hir::Constness::NotConst,
641 asyncness: hir::IsAsync::NotAsync,
642 abi: ExternAbi::Rust,
643 }
644 }
645
646 #[inline]
647 fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir> {
648 hir::Expr { hir_id: self.next_id(), kind, span }
649 }
650}
651
652struct SelfResolver<'a, 'b, 'hir> {
653 ctxt: &'a mut LoweringContext<'b, 'hir>,
654 path_id: NodeId,
655 self_param_id: NodeId,
656}
657
658impl SelfResolver<'_, '_, '_> {
659 fn try_replace_id(&mut self, id: NodeId) {
660 if let Some(res) = self.ctxt.get_partial_res(id)
661 && let Some(Res::Local(sig_id)) = res.full_res()
662 && sig_id == self.path_id
663 {
664 self.ctxt.partial_res_overrides.insert(id, self.self_param_id);
665 }
666 }
667}
668
669impl<'ast> Visitor<'ast> for SelfResolver<'_, '_, '_> {
670 fn visit_id(&mut self, id: NodeId) {
671 self.try_replace_id(id);
672 }
673}