1use std::iter;
40
41use ast::visit::Visitor;
42use hir::def::{DefKind, PartialRes, Res};
43use hir::{BodyId, HirId};
44use rustc_abi::ExternAbi;
45use rustc_ast::*;
46use rustc_attr_parsing::{AttributeParser, ShouldEmit};
47use rustc_data_structures::fx::FxHashSet;
48use rustc_errors::ErrorGuaranteed;
49use rustc_hir::Target;
50use rustc_hir::attrs::{AttributeKind, InlineAttr};
51use rustc_hir::def_id::{DefId, LocalDefId};
52use rustc_middle::span_bug;
53use rustc_middle::ty::{Asyncness, DelegationAttrs, DelegationFnSigAttrs, ResolverAstLowering};
54use rustc_span::symbol::kw;
55use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
56use smallvec::SmallVec;
57use {rustc_ast as ast, rustc_hir as hir};
58
59use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
60use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee};
61use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};
62
63pub(crate) struct DelegationResults<'hir> {
64 pub body_id: hir::BodyId,
65 pub sig: hir::FnSig<'hir>,
66 pub ident: Ident,
67 pub generics: &'hir hir::Generics<'hir>,
68}
69
70struct AttrAdditionInfo {
71 pub equals: fn(&hir::Attribute) -> bool,
72 pub kind: AttrAdditionKind,
73}
74
75enum AttrAdditionKind {
76 Default { factory: fn(Span) -> hir::Attribute },
77 Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute },
78}
79
80const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
81
82static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[
83 AttrAdditionInfo {
84 equals: |a| #[allow(non_exhaustive_omitted_patterns)] match a {
hir::Attribute::Parsed(AttributeKind::MustUse { .. }) => true,
_ => false,
}matches!(a, hir::Attribute::Parsed(AttributeKind::MustUse { .. })),
85 kind: AttrAdditionKind::Inherit {
86 factory: |span, original_attr| {
87 let reason = match original_attr {
88 hir::Attribute::Parsed(AttributeKind::MustUse { reason, .. }) => *reason,
89 _ => None,
90 };
91
92 hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
93 },
94 flag: DelegationFnSigAttrs::MUST_USE,
95 },
96 },
97 AttrAdditionInfo {
98 equals: |a| #[allow(non_exhaustive_omitted_patterns)] match a {
hir::Attribute::Parsed(AttributeKind::Inline(..)) => true,
_ => false,
}matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))),
99 kind: AttrAdditionKind::Default {
100 factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)),
101 },
102 },
103];
104
105type DelegationIdsVec = SmallVec<[DefId; 1]>;
106
107struct DelegationIds {
111 path: DelegationIdsVec,
112}
113
114impl DelegationIds {
115 fn new(path: DelegationIdsVec) -> Self {
116 if !!path.is_empty() {
::core::panicking::panic("assertion failed: !path.is_empty()")
};assert!(!path.is_empty());
117 Self { path }
118 }
119
120 fn root_function_id(&self) -> DefId {
122 *self.path.last().expect("Ids vector can't be empty")
123 }
124
125 fn delegee_id(&self) -> DefId {
128 *self.path.first().expect("Ids vector can't be empty")
129 }
130}
131
132impl<'hir> LoweringContext<'_, 'hir> {
133 fn is_method(&self, def_id: DefId, span: Span) -> bool {
134 match self.tcx.def_kind(def_id) {
135 DefKind::Fn => false,
136 DefKind::AssocFn => match def_id.as_local() {
137 Some(local_def_id) => self
138 .resolver
139 .delegation_fn_sigs
140 .get(&local_def_id)
141 .is_some_and(|sig| sig.has_self),
142 None => self.tcx.associated_item(def_id).is_method(),
143 },
144 _ => ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("unexpected DefKind for delegation item"))span_bug!(span, "unexpected DefKind for delegation item"),
145 }
146 }
147
148 pub(crate) fn lower_delegation(
149 &mut self,
150 delegation: &Delegation,
151 item_id: NodeId,
152 ) -> DelegationResults<'hir> {
153 let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
154
155 let ids = if let Some(delegation_info) =
157 self.resolver.delegation_infos.get(&self.local_def_id(item_id))
158 {
159 self.get_delegation_ids(delegation_info.resolution_node, span)
160 } else {
161 return self.generate_delegation_error(
162 self.dcx().span_delayed_bug(
163 span,
164 ::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),
165 ),
166 span,
167 delegation,
168 );
169 };
170
171 match ids {
172 Ok(ids) => {
173 self.add_attrs_if_needed(span, &ids);
174
175 let delegee_id = ids.delegee_id();
176 let root_function_id = ids.root_function_id();
177
178 let is_method = self.is_method(root_function_id, span);
182
183 let (param_count, c_variadic) = self.param_count(root_function_id);
186
187 let decl = self.lower_delegation_decl(delegee_id, param_count, c_variadic, span);
191
192 let sig = self.lower_delegation_sig(root_function_id, decl, span);
195
196 let body_id = self.lower_delegation_body(delegation, is_method, param_count, span);
197 let ident = self.lower_ident(delegation.ident);
198 let generics = self.lower_delegation_generics(span);
199 DelegationResults { body_id, sig, ident, generics }
200 }
201 Err(err) => self.generate_delegation_error(err, span, delegation),
202 }
203 }
204
205 fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) {
206 let new_attrs =
207 self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID));
208
209 if new_attrs.is_empty() {
210 return;
211 }
212
213 let new_arena_allocated_attrs = match self.attrs.get(&PARENT_ID) {
214 Some(existing_attrs) => self.arena.alloc_from_iter(
215 existing_attrs.iter().map(|a| a.clone()).chain(new_attrs.into_iter()),
216 ),
217 None => self.arena.alloc_from_iter(new_attrs.into_iter()),
218 };
219
220 self.attrs.insert(PARENT_ID, new_arena_allocated_attrs);
221 }
222
223 fn create_new_attrs(
224 &self,
225 candidate_additions: &[AttrAdditionInfo],
226 span: Span,
227 ids: &DelegationIds,
228 existing_attrs: Option<&&[hir::Attribute]>,
229 ) -> Vec<hir::Attribute> {
230 let defs_orig_attrs = ids
231 .path
232 .iter()
233 .map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id)))
234 .collect::<Vec<_>>();
235
236 candidate_additions
237 .iter()
238 .filter_map(|addition_info| {
239 if let Some(existing_attrs) = existing_attrs
240 && existing_attrs
241 .iter()
242 .any(|existing_attr| (addition_info.equals)(existing_attr))
243 {
244 return None;
245 }
246
247 match addition_info.kind {
248 AttrAdditionKind::Default { factory } => Some(factory(span)),
249 AttrAdditionKind::Inherit { flag, factory } => {
250 for (def_id, orig_attrs) in &defs_orig_attrs {
251 let original_attr = match def_id.as_local() {
252 Some(local_id) => self
253 .get_attrs(local_id)
254 .flags
255 .contains(flag)
256 .then(|| {
257 orig_attrs
258 .as_ref()
259 .map(|attrs| {
260 attrs.iter().find(|base_attr| {
261 (addition_info.equals)(base_attr)
262 })
263 })
264 .flatten()
265 })
266 .flatten(),
267 None => self
268 .tcx
269 .get_all_attrs(*def_id)
270 .iter()
271 .find(|base_attr| (addition_info.equals)(base_attr)),
272 };
273
274 if let Some(original_attr) = original_attr {
275 return Some(factory(span, original_attr));
276 }
277 }
278
279 None
280 }
281 }
282 })
283 .collect::<Vec<_>>()
284 }
285
286 fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
287 if let Some(local_id) = def_id.as_local() {
288 let attrs = &self.get_attrs(local_id).to_inherit;
289
290 if !attrs.is_empty() {
291 return Some(AttributeParser::parse_limited_all(
292 self.tcx.sess,
293 attrs,
294 None,
295 Target::Fn,
296 DUMMY_SP,
297 DUMMY_NODE_ID,
298 Some(self.tcx.features()),
299 ShouldEmit::Nothing,
300 ));
301 }
302 }
303
304 None
305 }
306
307 fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
308 if let Some(fn_sig) = self.resolver.delegation_fn_sigs.get(&local_id) {
310 &fn_sig.attrs
311 } else {
312 &self.resolver.delegation_infos[&local_id].attrs
313 }
314 }
315
316 fn get_delegation_ids(
317 &self,
318 mut node_id: NodeId,
319 span: Span,
320 ) -> Result<DelegationIds, ErrorGuaranteed> {
321 let mut visited: FxHashSet<NodeId> = Default::default();
322 let mut path: DelegationIdsVec = Default::default();
323
324 loop {
325 visited.insert(node_id);
326
327 let Some(def_id) = self.get_resolution_id(node_id) else {
328 return Err(self.tcx.dcx().span_delayed_bug(
329 span,
330 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("LoweringContext: couldn\'t resolve node {0:?} in delegation item",
node_id))
})format!(
331 "LoweringContext: couldn't resolve node {:?} in delegation item",
332 node_id
333 ),
334 ));
335 };
336
337 path.push(def_id);
338
339 if let Some(local_id) = def_id.as_local()
343 && let Some(delegation_info) = self.resolver.delegation_infos.get(&local_id)
344 {
345 node_id = delegation_info.resolution_node;
346 if visited.contains(&node_id) {
347 return Err(match visited.len() {
350 1 => self.dcx().emit_err(UnresolvedDelegationCallee { span }),
351 _ => self.dcx().emit_err(CycleInDelegationSignatureResolution { span }),
352 });
353 }
354 } else {
355 return Ok(DelegationIds::new(path));
356 }
357 }
358 }
359
360 fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
361 self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
362 }
363
364 fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
365 self.arena.alloc(hir::Generics {
366 params: &[],
367 predicates: &[],
368 has_where_clause_predicates: false,
369 where_clause_span: span,
370 span,
371 })
372 }
373
374 fn param_count(&self, def_id: DefId) -> (usize, bool ) {
376 if let Some(local_sig_id) = def_id.as_local() {
377 match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
378 Some(sig) => (sig.param_count, sig.c_variadic),
379 None => (0, false),
380 }
381 } else {
382 let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
383 (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
384 }
385 }
386
387 fn lower_delegation_decl(
388 &mut self,
389 sig_id: DefId,
390 param_count: usize,
391 c_variadic: bool,
392 span: Span,
393 ) -> &'hir hir::FnDecl<'hir> {
394 let decl_param_count = param_count - c_variadic as usize;
397 let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty {
398 hir_id: self.next_id(),
399 kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
400 span,
401 }));
402
403 let output = self.arena.alloc(hir::Ty {
404 hir_id: self.next_id(),
405 kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
406 span,
407 });
408
409 self.arena.alloc(hir::FnDecl {
410 inputs,
411 output: hir::FnRetTy::Return(output),
412 c_variadic,
413 lifetime_elision_allowed: true,
414 implicit_self: hir::ImplicitSelfKind::None,
415 })
416 }
417
418 fn lower_delegation_sig(
419 &mut self,
420 sig_id: DefId,
421 decl: &'hir hir::FnDecl<'hir>,
422 span: Span,
423 ) -> hir::FnSig<'hir> {
424 let header = if let Some(local_sig_id) = sig_id.as_local() {
425 match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
426 Some(sig) => {
427 let parent = self.tcx.parent(sig_id);
428 let default_safety =
432 if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
433 || self.tcx.def_kind(parent) == DefKind::ForeignMod
434 {
435 hir::Safety::Unsafe
436 } else {
437 hir::Safety::Safe
438 };
439 self.lower_fn_header(sig.header, default_safety, &[])
440 }
441 None => self.generate_header_error(),
442 }
443 } else {
444 let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
445 let asyncness = match self.tcx.asyncness(sig_id) {
446 Asyncness::Yes => hir::IsAsync::Async(span),
447 Asyncness::No => hir::IsAsync::NotAsync,
448 };
449 hir::FnHeader {
450 safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
451 hir::HeaderSafety::SafeTargetFeatures
452 } else {
453 hir::HeaderSafety::Normal(sig.safety)
454 },
455 constness: self.tcx.constness(sig_id),
456 asyncness,
457 abi: sig.abi,
458 }
459 };
460 hir::FnSig { decl, header, span }
461 }
462
463 fn generate_param(
464 &mut self,
465 is_method: bool,
466 idx: usize,
467 span: Span,
468 ) -> (hir::Param<'hir>, NodeId) {
469 let pat_node_id = self.next_node_id();
470 let pat_id = self.lower_node_id(pat_node_id);
471 let name = if is_method && idx == 0 {
473 kw::SelfLower
474 } else {
475 Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("arg{0}", idx))
})format!("arg{idx}"))
476 };
477 let ident = Ident::with_dummy_span(name);
478 let pat = self.arena.alloc(hir::Pat {
479 hir_id: pat_id,
480 kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, ident, None),
481 span,
482 default_binding_modes: false,
483 });
484
485 (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id)
486 }
487
488 fn generate_arg(
489 &mut self,
490 is_method: bool,
491 idx: usize,
492 param_id: HirId,
493 span: Span,
494 ) -> hir::Expr<'hir> {
495 let name = if is_method && idx == 0 {
497 kw::SelfLower
498 } else {
499 Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("arg{0}", idx))
})format!("arg{idx}"))
500 };
501 let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
502 ident: Ident::with_dummy_span(name),
503 hir_id: self.next_id(),
504 res: Res::Local(param_id),
505 args: None,
506 infer_args: false,
507 }));
508
509 let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments });
510 self.mk_expr(hir::ExprKind::Path(hir::QPath::Resolved(None, path)), span)
511 }
512
513 fn lower_delegation_body(
514 &mut self,
515 delegation: &Delegation,
516 is_method: bool,
517 param_count: usize,
518 span: Span,
519 ) -> BodyId {
520 let block = delegation.body.as_deref();
521
522 self.lower_body(|this| {
523 let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count);
524 let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);
525
526 for idx in 0..param_count {
527 let (param, pat_node_id) = this.generate_param(is_method, idx, span);
528 parameters.push(param);
529
530 let arg = if let Some(block) = block
531 && idx == 0
532 {
533 let mut self_resolver = SelfResolver {
534 resolver: this.resolver,
535 path_id: delegation.id,
536 self_param_id: pat_node_id,
537 };
538 self_resolver.visit_block(block);
539 this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);
541 this.lower_target_expr(&block)
542 } else {
543 this.generate_arg(is_method, idx, param.pat.hir_id, span)
544 };
545 args.push(arg);
546 }
547
548 let final_expr = this.finalize_body_lowering(delegation, args, span);
549 (this.arena.alloc_from_iter(parameters), final_expr)
550 })
551 }
552
553 fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
556 if let [stmt] = block.stmts.as_slice()
557 && let StmtKind::Expr(expr) = &stmt.kind
558 {
559 return self.lower_expr_mut(expr);
560 }
561
562 let block = self.lower_block(block, false);
563 self.mk_expr(hir::ExprKind::Block(block, None), block.span)
564 }
565
566 fn finalize_body_lowering(
582 &mut self,
583 delegation: &Delegation,
584 args: Vec<hir::Expr<'hir>>,
585 span: Span,
586 ) -> hir::Expr<'hir> {
587 let args = self.arena.alloc_from_iter(args);
588
589 let has_generic_args =
590 delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());
591
592 let call = if self
593 .get_resolution_id(delegation.id)
594 .map(|def_id| self.is_method(def_id, span))
595 .unwrap_or_default()
596 && delegation.qself.is_none()
597 && !has_generic_args
598 && !args.is_empty()
599 {
600 let ast_segment = delegation.path.segments.last().unwrap();
601 let segment = self.lower_path_segment(
602 delegation.path.span,
603 ast_segment,
604 ParamMode::Optional,
605 GenericArgsMode::Err,
606 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
607 None,
608 );
609 let segment = self.arena.alloc(segment);
610
611 self.arena.alloc(hir::Expr {
612 hir_id: self.next_id(),
613 kind: hir::ExprKind::MethodCall(segment, &args[0], &args[1..], span),
614 span,
615 })
616 } else {
617 let path = self.lower_qpath(
618 delegation.id,
619 &delegation.qself,
620 &delegation.path,
621 ParamMode::Optional,
622 AllowReturnTypeNotation::No,
623 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
624 None,
625 );
626
627 let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span));
628 self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span))
629 };
630 let block = self.arena.alloc(hir::Block {
631 stmts: &[],
632 expr: Some(call),
633 hir_id: self.next_id(),
634 rules: hir::BlockCheckMode::DefaultBlock,
635 span,
636 targeted_by_break: false,
637 });
638
639 self.mk_expr(hir::ExprKind::Block(block, None), span)
640 }
641
642 fn generate_delegation_error(
643 &mut self,
644 err: ErrorGuaranteed,
645 span: Span,
646 delegation: &Delegation,
647 ) -> DelegationResults<'hir> {
648 let generics = self.lower_delegation_generics(span);
649
650 let decl = self.arena.alloc(hir::FnDecl {
651 inputs: &[],
652 output: hir::FnRetTy::DefaultReturn(span),
653 c_variadic: false,
654 lifetime_elision_allowed: true,
655 implicit_self: hir::ImplicitSelfKind::None,
656 });
657
658 let header = self.generate_header_error();
659 let sig = hir::FnSig { decl, header, span };
660
661 let ident = self.lower_ident(delegation.ident);
662
663 let body_id = self.lower_body(|this| {
664 let body_expr = match delegation.body.as_ref() {
665 Some(box block) => {
666 let stmts = this.arena.alloc_from_iter([hir::Stmt {
672 hir_id: this.next_id(),
673 kind: rustc_hir::StmtKind::Semi(
674 this.arena.alloc(this.lower_target_expr(block)),
675 ),
676 span,
677 }]);
678
679 let block = this.arena.alloc(hir::Block {
680 stmts,
681 expr: None,
682 hir_id: this.next_id(),
683 rules: hir::BlockCheckMode::DefaultBlock,
684 span,
685 targeted_by_break: false,
686 });
687
688 hir::ExprKind::Block(block, None)
689 }
690 None => hir::ExprKind::Err(err),
691 };
692
693 (&[], this.mk_expr(body_expr, span))
694 });
695
696 DelegationResults { ident, generics, body_id, sig }
697 }
698
699 fn generate_header_error(&self) -> hir::FnHeader {
700 hir::FnHeader {
701 safety: hir::Safety::Safe.into(),
702 constness: hir::Constness::NotConst,
703 asyncness: hir::IsAsync::NotAsync,
704 abi: ExternAbi::Rust,
705 }
706 }
707
708 #[inline]
709 fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir> {
710 hir::Expr { hir_id: self.next_id(), kind, span }
711 }
712}
713
714struct SelfResolver<'a> {
715 resolver: &'a mut ResolverAstLowering,
716 path_id: NodeId,
717 self_param_id: NodeId,
718}
719
720impl<'a> SelfResolver<'a> {
721 fn try_replace_id(&mut self, id: NodeId) {
722 if let Some(res) = self.resolver.partial_res_map.get(&id)
723 && let Some(Res::Local(sig_id)) = res.full_res()
724 && sig_id == self.path_id
725 {
726 let new_res = PartialRes::new(Res::Local(self.self_param_id));
727 self.resolver.partial_res_map.insert(id, new_res);
728 }
729 }
730}
731
732impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a> {
733 fn visit_id(&mut self, id: NodeId) {
734 self.try_replace_id(id);
735 }
736}