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| 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| 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 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 _ => 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 = self.get_delegation_ids(
156 self.resolver.delegation_infos[&self.local_def_id(item_id)].resolution_node,
157 span,
158 );
159
160 match ids {
161 Ok(ids) => {
162 self.add_attrs_if_needed(span, &ids);
163
164 let delegee_id = ids.delegee_id();
165 let root_function_id = ids.root_function_id();
166
167 let is_method = self.is_method(root_function_id, span);
171
172 let (param_count, c_variadic) = self.param_count(root_function_id);
175
176 let decl = self.lower_delegation_decl(delegee_id, param_count, c_variadic, span);
180
181 let sig = self.lower_delegation_sig(root_function_id, decl, span);
184
185 let body_id = self.lower_delegation_body(delegation, is_method, param_count, span);
186 let ident = self.lower_ident(delegation.ident);
187 let generics = self.lower_delegation_generics(span);
188 DelegationResults { body_id, sig, ident, generics }
189 }
190 Err(err) => self.generate_delegation_error(err, span, delegation),
191 }
192 }
193
194 fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) {
195 let new_attrs =
196 self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID));
197
198 if new_attrs.is_empty() {
199 return;
200 }
201
202 let new_arena_allocated_attrs = match self.attrs.get(&PARENT_ID) {
203 Some(existing_attrs) => self.arena.alloc_from_iter(
204 existing_attrs.iter().map(|a| a.clone()).chain(new_attrs.into_iter()),
205 ),
206 None => self.arena.alloc_from_iter(new_attrs.into_iter()),
207 };
208
209 self.attrs.insert(PARENT_ID, new_arena_allocated_attrs);
210 }
211
212 fn create_new_attrs(
213 &self,
214 candidate_additions: &[AttrAdditionInfo],
215 span: Span,
216 ids: &DelegationIds,
217 existing_attrs: Option<&&[hir::Attribute]>,
218 ) -> Vec<hir::Attribute> {
219 let defs_orig_attrs = ids
220 .path
221 .iter()
222 .map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id)))
223 .collect::<Vec<_>>();
224
225 candidate_additions
226 .iter()
227 .filter_map(|addition_info| {
228 if let Some(existing_attrs) = existing_attrs
229 && existing_attrs
230 .iter()
231 .any(|existing_attr| (addition_info.equals)(existing_attr))
232 {
233 return None;
234 }
235
236 match addition_info.kind {
237 AttrAdditionKind::Default { factory } => Some(factory(span)),
238 AttrAdditionKind::Inherit { flag, factory } => {
239 for (def_id, orig_attrs) in &defs_orig_attrs {
240 let original_attr = match def_id.as_local() {
241 Some(local_id) => self
242 .get_attrs(local_id)
243 .flags
244 .contains(flag)
245 .then(|| {
246 orig_attrs
247 .as_ref()
248 .map(|attrs| {
249 attrs.iter().find(|base_attr| {
250 (addition_info.equals)(base_attr)
251 })
252 })
253 .flatten()
254 })
255 .flatten(),
256 None => self
257 .tcx
258 .get_all_attrs(*def_id)
259 .iter()
260 .find(|base_attr| (addition_info.equals)(base_attr)),
261 };
262
263 if let Some(original_attr) = original_attr {
264 return Some(factory(span, original_attr));
265 }
266 }
267
268 None
269 }
270 }
271 })
272 .collect::<Vec<_>>()
273 }
274
275 fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
276 if let Some(local_id) = def_id.as_local() {
277 let attrs = &self.get_attrs(local_id).to_inherit;
278
279 if !attrs.is_empty() {
280 return Some(AttributeParser::parse_limited_all(
281 self.tcx.sess,
282 attrs,
283 None,
284 Target::Fn,
285 DUMMY_SP,
286 DUMMY_NODE_ID,
287 Some(self.tcx.features()),
288 ShouldEmit::Nothing,
289 ));
290 }
291 }
292
293 None
294 }
295
296 fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
297 if let Some(fn_sig) = self.resolver.delegation_fn_sigs.get(&local_id) {
299 &fn_sig.attrs
300 } else {
301 &self.resolver.delegation_infos[&local_id].attrs
302 }
303 }
304
305 fn get_delegation_ids(
306 &self,
307 mut node_id: NodeId,
308 span: Span,
309 ) -> Result<DelegationIds, ErrorGuaranteed> {
310 let mut visited: FxHashSet<NodeId> = Default::default();
311 let mut path: DelegationIdsVec = Default::default();
312
313 loop {
314 visited.insert(node_id);
315
316 let Some(def_id) = self.get_resolution_id(node_id) else {
317 return Err(self.tcx.dcx().span_delayed_bug(
318 span,
319 format!(
320 "LoweringContext: couldn't resolve node {:?} in delegation item",
321 node_id
322 ),
323 ));
324 };
325
326 path.push(def_id);
327
328 if let Some(local_id) = def_id.as_local()
332 && let Some(delegation_info) = self.resolver.delegation_infos.get(&local_id)
333 {
334 node_id = delegation_info.resolution_node;
335 if visited.contains(&node_id) {
336 return Err(match visited.len() {
339 1 => self.dcx().emit_err(UnresolvedDelegationCallee { span }),
340 _ => self.dcx().emit_err(CycleInDelegationSignatureResolution { span }),
341 });
342 }
343 } else {
344 return Ok(DelegationIds::new(path));
345 }
346 }
347 }
348
349 fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
350 self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
351 }
352
353 fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
354 self.arena.alloc(hir::Generics {
355 params: &[],
356 predicates: &[],
357 has_where_clause_predicates: false,
358 where_clause_span: span,
359 span,
360 })
361 }
362
363 fn param_count(&self, def_id: DefId) -> (usize, bool ) {
365 if let Some(local_sig_id) = def_id.as_local() {
366 match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
367 Some(sig) => (sig.param_count, sig.c_variadic),
368 None => (0, false),
369 }
370 } else {
371 let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
372 (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
373 }
374 }
375
376 fn lower_delegation_decl(
377 &mut self,
378 sig_id: DefId,
379 param_count: usize,
380 c_variadic: bool,
381 span: Span,
382 ) -> &'hir hir::FnDecl<'hir> {
383 let decl_param_count = param_count - c_variadic as usize;
386 let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty {
387 hir_id: self.next_id(),
388 kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
389 span,
390 }));
391
392 let output = self.arena.alloc(hir::Ty {
393 hir_id: self.next_id(),
394 kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
395 span,
396 });
397
398 self.arena.alloc(hir::FnDecl {
399 inputs,
400 output: hir::FnRetTy::Return(output),
401 c_variadic,
402 lifetime_elision_allowed: true,
403 implicit_self: hir::ImplicitSelfKind::None,
404 })
405 }
406
407 fn lower_delegation_sig(
408 &mut self,
409 sig_id: DefId,
410 decl: &'hir hir::FnDecl<'hir>,
411 span: Span,
412 ) -> hir::FnSig<'hir> {
413 let header = if let Some(local_sig_id) = sig_id.as_local() {
414 match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
415 Some(sig) => {
416 let parent = self.tcx.parent(sig_id);
417 let default_safety =
421 if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
422 || self.tcx.def_kind(parent) == DefKind::ForeignMod
423 {
424 hir::Safety::Unsafe
425 } else {
426 hir::Safety::Safe
427 };
428 self.lower_fn_header(sig.header, default_safety, &[])
429 }
430 None => self.generate_header_error(),
431 }
432 } else {
433 let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
434 let asyncness = match self.tcx.asyncness(sig_id) {
435 Asyncness::Yes => hir::IsAsync::Async(span),
436 Asyncness::No => hir::IsAsync::NotAsync,
437 };
438 hir::FnHeader {
439 safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
440 hir::HeaderSafety::SafeTargetFeatures
441 } else {
442 hir::HeaderSafety::Normal(sig.safety)
443 },
444 constness: self.tcx.constness(sig_id),
445 asyncness,
446 abi: sig.abi,
447 }
448 };
449 hir::FnSig { decl, header, span }
450 }
451
452 fn generate_param(
453 &mut self,
454 is_method: bool,
455 idx: usize,
456 span: Span,
457 ) -> (hir::Param<'hir>, NodeId) {
458 let pat_node_id = self.next_node_id();
459 let pat_id = self.lower_node_id(pat_node_id);
460 let name = if is_method && idx == 0 {
462 kw::SelfLower
463 } else {
464 Symbol::intern(&format!("arg{idx}"))
465 };
466 let ident = Ident::with_dummy_span(name);
467 let pat = self.arena.alloc(hir::Pat {
468 hir_id: pat_id,
469 kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, ident, None),
470 span,
471 default_binding_modes: false,
472 });
473
474 (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id)
475 }
476
477 fn generate_arg(
478 &mut self,
479 is_method: bool,
480 idx: usize,
481 param_id: HirId,
482 span: Span,
483 ) -> hir::Expr<'hir> {
484 let name = if is_method && idx == 0 {
486 kw::SelfLower
487 } else {
488 Symbol::intern(&format!("arg{idx}"))
489 };
490 let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
491 ident: Ident::with_dummy_span(name),
492 hir_id: self.next_id(),
493 res: Res::Local(param_id),
494 args: None,
495 infer_args: false,
496 }));
497
498 let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments });
499 self.mk_expr(hir::ExprKind::Path(hir::QPath::Resolved(None, path)), span)
500 }
501
502 fn lower_delegation_body(
503 &mut self,
504 delegation: &Delegation,
505 is_method: bool,
506 param_count: usize,
507 span: Span,
508 ) -> BodyId {
509 let block = delegation.body.as_deref();
510
511 self.lower_body(|this| {
512 let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count);
513 let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);
514
515 for idx in 0..param_count {
516 let (param, pat_node_id) = this.generate_param(is_method, idx, span);
517 parameters.push(param);
518
519 let arg = if let Some(block) = block
520 && idx == 0
521 {
522 let mut self_resolver = SelfResolver {
523 resolver: this.resolver,
524 path_id: delegation.id,
525 self_param_id: pat_node_id,
526 };
527 self_resolver.visit_block(block);
528 this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);
530 this.lower_target_expr(&block)
531 } else {
532 this.generate_arg(is_method, idx, param.pat.hir_id, span)
533 };
534 args.push(arg);
535 }
536
537 let final_expr = this.finalize_body_lowering(delegation, args, span);
538 (this.arena.alloc_from_iter(parameters), final_expr)
539 })
540 }
541
542 fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
545 if let [stmt] = block.stmts.as_slice()
546 && let StmtKind::Expr(expr) = &stmt.kind
547 {
548 return self.lower_expr_mut(expr);
549 }
550
551 let block = self.lower_block(block, false);
552 self.mk_expr(hir::ExprKind::Block(block, None), block.span)
553 }
554
555 fn finalize_body_lowering(
571 &mut self,
572 delegation: &Delegation,
573 args: Vec<hir::Expr<'hir>>,
574 span: Span,
575 ) -> hir::Expr<'hir> {
576 let args = self.arena.alloc_from_iter(args);
577
578 let has_generic_args =
579 delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());
580
581 let call = if self
582 .get_resolution_id(delegation.id)
583 .map(|def_id| self.is_method(def_id, span))
584 .unwrap_or_default()
585 && delegation.qself.is_none()
586 && !has_generic_args
587 && !args.is_empty()
588 {
589 let ast_segment = delegation.path.segments.last().unwrap();
590 let segment = self.lower_path_segment(
591 delegation.path.span,
592 ast_segment,
593 ParamMode::Optional,
594 GenericArgsMode::Err,
595 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
596 None,
597 );
598 let segment = self.arena.alloc(segment);
599
600 self.arena.alloc(hir::Expr {
601 hir_id: self.next_id(),
602 kind: hir::ExprKind::MethodCall(segment, &args[0], &args[1..], span),
603 span,
604 })
605 } else {
606 let path = self.lower_qpath(
607 delegation.id,
608 &delegation.qself,
609 &delegation.path,
610 ParamMode::Optional,
611 AllowReturnTypeNotation::No,
612 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
613 None,
614 );
615
616 let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span));
617 self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span))
618 };
619 let block = self.arena.alloc(hir::Block {
620 stmts: &[],
621 expr: Some(call),
622 hir_id: self.next_id(),
623 rules: hir::BlockCheckMode::DefaultBlock,
624 span,
625 targeted_by_break: false,
626 });
627
628 self.mk_expr(hir::ExprKind::Block(block, None), span)
629 }
630
631 fn generate_delegation_error(
632 &mut self,
633 err: ErrorGuaranteed,
634 span: Span,
635 delegation: &Delegation,
636 ) -> DelegationResults<'hir> {
637 let generics = self.lower_delegation_generics(span);
638
639 let decl = self.arena.alloc(hir::FnDecl {
640 inputs: &[],
641 output: hir::FnRetTy::DefaultReturn(span),
642 c_variadic: false,
643 lifetime_elision_allowed: true,
644 implicit_self: hir::ImplicitSelfKind::None,
645 });
646
647 let header = self.generate_header_error();
648 let sig = hir::FnSig { decl, header, span };
649
650 let ident = self.lower_ident(delegation.ident);
651
652 let body_id = self.lower_body(|this| {
653 let body_expr = match delegation.body.as_ref() {
654 Some(box block) => {
655 let stmts = this.arena.alloc_from_iter([hir::Stmt {
661 hir_id: this.next_id(),
662 kind: rustc_hir::StmtKind::Semi(
663 this.arena.alloc(this.lower_target_expr(block)),
664 ),
665 span,
666 }]);
667
668 let block = this.arena.alloc(hir::Block {
669 stmts,
670 expr: None,
671 hir_id: this.next_id(),
672 rules: hir::BlockCheckMode::DefaultBlock,
673 span,
674 targeted_by_break: false,
675 });
676
677 hir::ExprKind::Block(block, None)
678 }
679 None => hir::ExprKind::Err(err),
680 };
681
682 (&[], this.mk_expr(body_expr, span))
683 });
684
685 DelegationResults { ident, generics, body_id, sig }
686 }
687
688 fn generate_header_error(&self) -> hir::FnHeader {
689 hir::FnHeader {
690 safety: hir::Safety::Safe.into(),
691 constness: hir::Constness::NotConst,
692 asyncness: hir::IsAsync::NotAsync,
693 abi: ExternAbi::Rust,
694 }
695 }
696
697 #[inline]
698 fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir> {
699 hir::Expr { hir_id: self.next_id(), kind, span }
700 }
701}
702
703struct SelfResolver<'a> {
704 resolver: &'a mut ResolverAstLowering,
705 path_id: NodeId,
706 self_param_id: NodeId,
707}
708
709impl<'a> SelfResolver<'a> {
710 fn try_replace_id(&mut self, id: NodeId) {
711 if let Some(res) = self.resolver.partial_res_map.get(&id)
712 && let Some(Res::Local(sig_id)) = res.full_res()
713 && sig_id == self.path_id
714 {
715 let new_res = PartialRes::new(Res::Local(self.self_param_id));
716 self.resolver.partial_res_map.insert(id, new_res);
717 }
718 }
719}
720
721impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a> {
722 fn visit_id(&mut self, id: NodeId) {
723 self.try_replace_id(id);
724 }
725}