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 =>
268 {
269 #[allow(deprecated)]
270 self.tcx
271 .get_all_attrs(*def_id)
272 .iter()
273 .find(|base_attr| (addition_info.equals)(base_attr))
274 }
275 };
276
277 if let Some(original_attr) = original_attr {
278 return Some(factory(span, original_attr));
279 }
280 }
281
282 None
283 }
284 }
285 })
286 .collect::<Vec<_>>()
287 }
288
289 fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
290 if let Some(local_id) = def_id.as_local() {
291 let attrs = &self.get_attrs(local_id).to_inherit;
292
293 if !attrs.is_empty() {
294 return Some(AttributeParser::parse_limited_all(
295 self.tcx.sess,
296 attrs,
297 None,
298 Target::Fn,
299 DUMMY_SP,
300 DUMMY_NODE_ID,
301 Some(self.tcx.features()),
302 ShouldEmit::Nothing,
303 ));
304 }
305 }
306
307 None
308 }
309
310 fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
311 if let Some(fn_sig) = self.resolver.delegation_fn_sigs.get(&local_id) {
313 &fn_sig.attrs
314 } else {
315 &self.resolver.delegation_infos[&local_id].attrs
316 }
317 }
318
319 fn get_delegation_ids(
320 &self,
321 mut node_id: NodeId,
322 span: Span,
323 ) -> Result<DelegationIds, ErrorGuaranteed> {
324 let mut visited: FxHashSet<NodeId> = Default::default();
325 let mut path: DelegationIdsVec = Default::default();
326
327 loop {
328 visited.insert(node_id);
329
330 let Some(def_id) = self.get_resolution_id(node_id) else {
331 return Err(self.tcx.dcx().span_delayed_bug(
332 span,
333 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("LoweringContext: couldn\'t resolve node {0:?} in delegation item",
node_id))
})format!(
334 "LoweringContext: couldn't resolve node {:?} in delegation item",
335 node_id
336 ),
337 ));
338 };
339
340 path.push(def_id);
341
342 if let Some(local_id) = def_id.as_local()
346 && let Some(delegation_info) = self.resolver.delegation_infos.get(&local_id)
347 {
348 node_id = delegation_info.resolution_node;
349 if visited.contains(&node_id) {
350 return Err(match visited.len() {
353 1 => self.dcx().emit_err(UnresolvedDelegationCallee { span }),
354 _ => self.dcx().emit_err(CycleInDelegationSignatureResolution { span }),
355 });
356 }
357 } else {
358 return Ok(DelegationIds::new(path));
359 }
360 }
361 }
362
363 fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
364 self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
365 }
366
367 fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
368 self.arena.alloc(hir::Generics {
369 params: &[],
370 predicates: &[],
371 has_where_clause_predicates: false,
372 where_clause_span: span,
373 span,
374 })
375 }
376
377 fn param_count(&self, def_id: DefId) -> (usize, bool ) {
379 if let Some(local_sig_id) = def_id.as_local() {
380 match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
381 Some(sig) => (sig.param_count, sig.c_variadic),
382 None => (0, false),
383 }
384 } else {
385 let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
386 (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
387 }
388 }
389
390 fn lower_delegation_decl(
391 &mut self,
392 sig_id: DefId,
393 param_count: usize,
394 c_variadic: bool,
395 span: Span,
396 ) -> &'hir hir::FnDecl<'hir> {
397 let decl_param_count = param_count - c_variadic as usize;
400 let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty {
401 hir_id: self.next_id(),
402 kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
403 span,
404 }));
405
406 let output = self.arena.alloc(hir::Ty {
407 hir_id: self.next_id(),
408 kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
409 span,
410 });
411
412 self.arena.alloc(hir::FnDecl {
413 inputs,
414 output: hir::FnRetTy::Return(output),
415 c_variadic,
416 lifetime_elision_allowed: true,
417 implicit_self: hir::ImplicitSelfKind::None,
418 })
419 }
420
421 fn lower_delegation_sig(
422 &mut self,
423 sig_id: DefId,
424 decl: &'hir hir::FnDecl<'hir>,
425 span: Span,
426 ) -> hir::FnSig<'hir> {
427 let header = if let Some(local_sig_id) = sig_id.as_local() {
428 match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
429 Some(sig) => {
430 let parent = self.tcx.parent(sig_id);
431 let default_safety =
435 if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
436 || self.tcx.def_kind(parent) == DefKind::ForeignMod
437 {
438 hir::Safety::Unsafe
439 } else {
440 hir::Safety::Safe
441 };
442 self.lower_fn_header(sig.header, default_safety, &[])
443 }
444 None => self.generate_header_error(),
445 }
446 } else {
447 let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
448 let asyncness = match self.tcx.asyncness(sig_id) {
449 Asyncness::Yes => hir::IsAsync::Async(span),
450 Asyncness::No => hir::IsAsync::NotAsync,
451 };
452 hir::FnHeader {
453 safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
454 hir::HeaderSafety::SafeTargetFeatures
455 } else {
456 hir::HeaderSafety::Normal(sig.safety)
457 },
458 constness: self.tcx.constness(sig_id),
459 asyncness,
460 abi: sig.abi,
461 }
462 };
463 hir::FnSig { decl, header, span }
464 }
465
466 fn generate_param(
467 &mut self,
468 is_method: bool,
469 idx: usize,
470 span: Span,
471 ) -> (hir::Param<'hir>, NodeId) {
472 let pat_node_id = self.next_node_id();
473 let pat_id = self.lower_node_id(pat_node_id);
474 let name = if is_method && idx == 0 {
476 kw::SelfLower
477 } else {
478 Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("arg{0}", idx))
})format!("arg{idx}"))
479 };
480 let ident = Ident::with_dummy_span(name);
481 let pat = self.arena.alloc(hir::Pat {
482 hir_id: pat_id,
483 kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, ident, None),
484 span,
485 default_binding_modes: false,
486 });
487
488 (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id)
489 }
490
491 fn generate_arg(
492 &mut self,
493 is_method: bool,
494 idx: usize,
495 param_id: HirId,
496 span: Span,
497 ) -> hir::Expr<'hir> {
498 let name = if is_method && idx == 0 {
500 kw::SelfLower
501 } else {
502 Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("arg{0}", idx))
})format!("arg{idx}"))
503 };
504 let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
505 ident: Ident::with_dummy_span(name),
506 hir_id: self.next_id(),
507 res: Res::Local(param_id),
508 args: None,
509 infer_args: false,
510 }));
511
512 let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments });
513 self.mk_expr(hir::ExprKind::Path(hir::QPath::Resolved(None, path)), span)
514 }
515
516 fn lower_delegation_body(
517 &mut self,
518 delegation: &Delegation,
519 is_method: bool,
520 param_count: usize,
521 span: Span,
522 ) -> BodyId {
523 let block = delegation.body.as_deref();
524
525 self.lower_body(|this| {
526 let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count);
527 let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);
528
529 for idx in 0..param_count {
530 let (param, pat_node_id) = this.generate_param(is_method, idx, span);
531 parameters.push(param);
532
533 let arg = if let Some(block) = block
534 && idx == 0
535 {
536 let mut self_resolver = SelfResolver {
537 resolver: this.resolver,
538 path_id: delegation.id,
539 self_param_id: pat_node_id,
540 };
541 self_resolver.visit_block(block);
542 this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);
544 this.lower_target_expr(&block)
545 } else {
546 this.generate_arg(is_method, idx, param.pat.hir_id, span)
547 };
548 args.push(arg);
549 }
550
551 let final_expr = this.finalize_body_lowering(delegation, args, span);
552 (this.arena.alloc_from_iter(parameters), final_expr)
553 })
554 }
555
556 fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
559 if let [stmt] = block.stmts.as_slice()
560 && let StmtKind::Expr(expr) = &stmt.kind
561 {
562 return self.lower_expr_mut(expr);
563 }
564
565 let block = self.lower_block(block, false);
566 self.mk_expr(hir::ExprKind::Block(block, None), block.span)
567 }
568
569 fn finalize_body_lowering(
585 &mut self,
586 delegation: &Delegation,
587 args: Vec<hir::Expr<'hir>>,
588 span: Span,
589 ) -> hir::Expr<'hir> {
590 let args = self.arena.alloc_from_iter(args);
591
592 let has_generic_args =
593 delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());
594
595 let call = if self
596 .get_resolution_id(delegation.id)
597 .map(|def_id| self.is_method(def_id, span))
598 .unwrap_or_default()
599 && delegation.qself.is_none()
600 && !has_generic_args
601 && !args.is_empty()
602 {
603 let ast_segment = delegation.path.segments.last().unwrap();
604 let segment = self.lower_path_segment(
605 delegation.path.span,
606 ast_segment,
607 ParamMode::Optional,
608 GenericArgsMode::Err,
609 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
610 None,
611 );
612 let segment = self.arena.alloc(segment);
613
614 self.arena.alloc(hir::Expr {
615 hir_id: self.next_id(),
616 kind: hir::ExprKind::MethodCall(segment, &args[0], &args[1..], span),
617 span,
618 })
619 } else {
620 let path = self.lower_qpath(
621 delegation.id,
622 &delegation.qself,
623 &delegation.path,
624 ParamMode::Optional,
625 AllowReturnTypeNotation::No,
626 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
627 None,
628 );
629
630 let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span));
631 self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span))
632 };
633 let block = self.arena.alloc(hir::Block {
634 stmts: &[],
635 expr: Some(call),
636 hir_id: self.next_id(),
637 rules: hir::BlockCheckMode::DefaultBlock,
638 span,
639 targeted_by_break: false,
640 });
641
642 self.mk_expr(hir::ExprKind::Block(block, None), span)
643 }
644
645 fn generate_delegation_error(
646 &mut self,
647 err: ErrorGuaranteed,
648 span: Span,
649 delegation: &Delegation,
650 ) -> DelegationResults<'hir> {
651 let generics = self.lower_delegation_generics(span);
652
653 let decl = self.arena.alloc(hir::FnDecl {
654 inputs: &[],
655 output: hir::FnRetTy::DefaultReturn(span),
656 c_variadic: false,
657 lifetime_elision_allowed: true,
658 implicit_self: hir::ImplicitSelfKind::None,
659 });
660
661 let header = self.generate_header_error();
662 let sig = hir::FnSig { decl, header, span };
663
664 let ident = self.lower_ident(delegation.ident);
665
666 let body_id = self.lower_body(|this| {
667 let body_expr = match delegation.body.as_ref() {
668 Some(box block) => {
669 let stmts = this.arena.alloc_from_iter([hir::Stmt {
675 hir_id: this.next_id(),
676 kind: rustc_hir::StmtKind::Semi(
677 this.arena.alloc(this.lower_target_expr(block)),
678 ),
679 span,
680 }]);
681
682 let block = this.arena.alloc(hir::Block {
683 stmts,
684 expr: None,
685 hir_id: this.next_id(),
686 rules: hir::BlockCheckMode::DefaultBlock,
687 span,
688 targeted_by_break: false,
689 });
690
691 hir::ExprKind::Block(block, None)
692 }
693 None => hir::ExprKind::Err(err),
694 };
695
696 (&[], this.mk_expr(body_expr, span))
697 });
698
699 DelegationResults { ident, generics, body_id, sig }
700 }
701
702 fn generate_header_error(&self) -> hir::FnHeader {
703 hir::FnHeader {
704 safety: hir::Safety::Safe.into(),
705 constness: hir::Constness::NotConst,
706 asyncness: hir::IsAsync::NotAsync,
707 abi: ExternAbi::Rust,
708 }
709 }
710
711 #[inline]
712 fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir> {
713 hir::Expr { hir_id: self.next_id(), kind, span }
714 }
715}
716
717struct SelfResolver<'a> {
718 resolver: &'a mut ResolverAstLowering,
719 path_id: NodeId,
720 self_param_id: NodeId,
721}
722
723impl<'a> SelfResolver<'a> {
724 fn try_replace_id(&mut self, id: NodeId) {
725 if let Some(res) = self.resolver.partial_res_map.get(&id)
726 && let Some(Res::Local(sig_id)) = res.full_res()
727 && sig_id == self.path_id
728 {
729 let new_res = PartialRes::new(Res::Local(self.self_param_id));
730 self.resolver.partial_res_map.insert(id, new_res);
731 }
732 }
733}
734
735impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a> {
736 fn visit_id(&mut self, id: NodeId) {
737 self.try_replace_id(id);
738 }
739}