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_errors::ErrorGuaranteed;
47use rustc_hir::def_id::DefId;
48use rustc_middle::span_bug;
49use rustc_middle::ty::{Asyncness, ResolverAstLowering};
50use rustc_span::{Ident, Span};
51use {rustc_ast as ast, rustc_hir as hir};
52
53use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
54use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};
55
56pub(crate) struct DelegationResults<'hir> {
57 pub body_id: hir::BodyId,
58 pub sig: hir::FnSig<'hir>,
59 pub generics: &'hir hir::Generics<'hir>,
60}
61
62impl<'hir> LoweringContext<'_, 'hir> {
63 pub(crate) fn delegatee_is_method(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool {
65 let sig_id = self.get_delegation_sig_id(item_id, path_id, span);
66 let Ok(sig_id) = sig_id else {
67 return false;
68 };
69 self.is_method(sig_id, span)
70 }
71
72 fn is_method(&self, def_id: DefId, span: Span) -> bool {
73 match self.tcx.def_kind(def_id) {
74 DefKind::Fn => false,
75 DefKind::AssocFn => match def_id.as_local() {
76 Some(local_def_id) => self
77 .resolver
78 .delegation_fn_sigs
79 .get(&local_def_id)
80 .is_some_and(|sig| sig.has_self),
81 None => self.tcx.associated_item(def_id).fn_has_self_parameter,
82 },
83 _ => span_bug!(span, "unexpected DefKind for delegation item"),
84 }
85 }
86
87 pub(crate) fn lower_delegation(
88 &mut self,
89 delegation: &Delegation,
90 item_id: NodeId,
91 ) -> DelegationResults<'hir> {
92 let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
93 let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span);
94 match sig_id {
95 Ok(sig_id) => {
96 let (param_count, c_variadic) = self.param_count(sig_id);
97 let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span);
98 let sig = self.lower_delegation_sig(sig_id, decl, span);
99 let body_id = self.lower_delegation_body(delegation, param_count, span);
100
101 let generics = self.lower_delegation_generics(span);
102 DelegationResults { body_id, sig, generics }
103 }
104 Err(err) => self.generate_delegation_error(err, span),
105 }
106 }
107
108 fn get_delegation_sig_id(
109 &self,
110 item_id: NodeId,
111 path_id: NodeId,
112 span: Span,
113 ) -> Result<DefId, ErrorGuaranteed> {
114 let sig_id = if self.is_in_trait_impl { item_id } else { path_id };
115 self.get_resolution_id(sig_id, span)
116 }
117
118 fn get_resolution_id(&self, node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
119 let def_id =
120 self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id());
121 def_id.ok_or_else(|| {
122 self.tcx.dcx().span_delayed_bug(
123 span,
124 format!("LoweringContext: couldn't resolve node {:?} in delegation item", node_id),
125 )
126 })
127 }
128
129 fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
130 self.arena.alloc(hir::Generics {
131 params: &[],
132 predicates: &[],
133 has_where_clause_predicates: false,
134 where_clause_span: span,
135 span,
136 })
137 }
138
139 fn param_count(&self, sig_id: DefId) -> (usize, bool ) {
141 if let Some(local_sig_id) = sig_id.as_local() {
142 match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
145 Some(sig) => (sig.param_count, sig.c_variadic),
146 None => (0, false),
147 }
148 } else {
149 let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
150 (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
151 }
152 }
153
154 fn lower_delegation_decl(
155 &mut self,
156 sig_id: DefId,
157 param_count: usize,
158 c_variadic: bool,
159 span: Span,
160 ) -> &'hir hir::FnDecl<'hir> {
161 let decl_param_count = param_count - c_variadic as usize;
164 let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty {
165 hir_id: self.next_id(),
166 kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
167 span,
168 }));
169
170 let output = self.arena.alloc(hir::Ty {
171 hir_id: self.next_id(),
172 kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
173 span,
174 });
175
176 self.arena.alloc(hir::FnDecl {
177 inputs,
178 output: hir::FnRetTy::Return(output),
179 c_variadic,
180 lifetime_elision_allowed: true,
181 implicit_self: hir::ImplicitSelfKind::None,
182 })
183 }
184
185 fn lower_delegation_sig(
186 &mut self,
187 sig_id: DefId,
188 decl: &'hir hir::FnDecl<'hir>,
189 span: Span,
190 ) -> hir::FnSig<'hir> {
191 let header = if let Some(local_sig_id) = sig_id.as_local() {
192 match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
193 Some(sig) => {
194 let parent = self.tcx.parent(sig_id);
195 let default_safety =
199 if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod {
200 hir::Safety::Unsafe
201 } else {
202 hir::Safety::Safe
203 };
204 self.lower_fn_header(sig.header, default_safety, &[])
205 }
206 None => self.generate_header_error(),
207 }
208 } else {
209 let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
210 let asyncness = match self.tcx.asyncness(sig_id) {
211 Asyncness::Yes => hir::IsAsync::Async(span),
212 Asyncness::No => hir::IsAsync::NotAsync,
213 };
214 hir::FnHeader {
215 safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
216 hir::HeaderSafety::SafeTargetFeatures
217 } else {
218 hir::HeaderSafety::Normal(sig.safety)
219 },
220 constness: self.tcx.constness(sig_id),
221 asyncness,
222 abi: sig.abi,
223 }
224 };
225 hir::FnSig { decl, header, span }
226 }
227
228 fn generate_param(&mut self, span: Span) -> (hir::Param<'hir>, NodeId) {
229 let pat_node_id = self.next_node_id();
230 let pat_id = self.lower_node_id(pat_node_id);
231 let pat = self.arena.alloc(hir::Pat {
232 hir_id: pat_id,
233 kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, Ident::empty(), None),
234 span,
235 default_binding_modes: false,
236 });
237
238 (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id)
239 }
240
241 fn generate_arg(&mut self, param_id: HirId, span: Span) -> hir::Expr<'hir> {
242 let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
243 ident: Ident::empty(),
244 hir_id: self.next_id(),
245 res: Res::Local(param_id),
246 args: None,
247 infer_args: false,
248 }));
249
250 let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments });
251 self.mk_expr(hir::ExprKind::Path(hir::QPath::Resolved(None, path)), span)
252 }
253
254 fn lower_delegation_body(
255 &mut self,
256 delegation: &Delegation,
257 param_count: usize,
258 span: Span,
259 ) -> BodyId {
260 let block = delegation.body.as_deref();
261
262 self.lower_body(|this| {
263 let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count);
264 let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);
265
266 for idx in 0..param_count {
267 let (param, pat_node_id) = this.generate_param(span);
268 parameters.push(param);
269
270 let arg = if let Some(block) = block
271 && idx == 0
272 {
273 let mut self_resolver = SelfResolver {
274 resolver: this.resolver,
275 path_id: delegation.id,
276 self_param_id: pat_node_id,
277 };
278 self_resolver.visit_block(block);
279 this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);
281 this.lower_target_expr(&block)
282 } else {
283 this.generate_arg(param.pat.hir_id, span)
284 };
285 args.push(arg);
286 }
287
288 let final_expr = this.finalize_body_lowering(delegation, args, span);
289 (this.arena.alloc_from_iter(parameters), final_expr)
290 })
291 }
292
293 fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
296 if let [stmt] = block.stmts.as_slice()
297 && let StmtKind::Expr(expr) = &stmt.kind
298 {
299 return self.lower_expr_mut(expr);
300 }
301
302 let block = self.lower_block(block, false);
303 self.mk_expr(hir::ExprKind::Block(block, None), block.span)
304 }
305
306 fn finalize_body_lowering(
322 &mut self,
323 delegation: &Delegation,
324 args: Vec<hir::Expr<'hir>>,
325 span: Span,
326 ) -> hir::Expr<'hir> {
327 let args = self.arena.alloc_from_iter(args);
328
329 let has_generic_args =
330 delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());
331
332 let call = if self
333 .get_resolution_id(delegation.id, span)
334 .and_then(|def_id| Ok(self.is_method(def_id, span)))
335 .unwrap_or_default()
336 && delegation.qself.is_none()
337 && !has_generic_args
338 && !args.is_empty()
339 {
340 let ast_segment = delegation.path.segments.last().unwrap();
341 let segment = self.lower_path_segment(
342 delegation.path.span,
343 ast_segment,
344 ParamMode::Optional,
345 GenericArgsMode::Err,
346 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
347 None,
348 );
349 let segment = self.arena.alloc(segment);
350
351 self.arena.alloc(hir::Expr {
352 hir_id: self.next_id(),
353 kind: hir::ExprKind::MethodCall(segment, &args[0], &args[1..], span),
354 span,
355 })
356 } else {
357 let path = self.lower_qpath(
358 delegation.id,
359 &delegation.qself,
360 &delegation.path,
361 ParamMode::Optional,
362 AllowReturnTypeNotation::No,
363 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
364 None,
365 );
366
367 let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span));
368 self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span))
369 };
370 let block = self.arena.alloc(hir::Block {
371 stmts: &[],
372 expr: Some(call),
373 hir_id: self.next_id(),
374 rules: hir::BlockCheckMode::DefaultBlock,
375 span,
376 targeted_by_break: false,
377 });
378
379 self.mk_expr(hir::ExprKind::Block(block, None), span)
380 }
381
382 fn generate_delegation_error(
383 &mut self,
384 err: ErrorGuaranteed,
385 span: Span,
386 ) -> DelegationResults<'hir> {
387 let generics = self.lower_delegation_generics(span);
388
389 let decl = self.arena.alloc(hir::FnDecl {
390 inputs: &[],
391 output: hir::FnRetTy::DefaultReturn(span),
392 c_variadic: false,
393 lifetime_elision_allowed: true,
394 implicit_self: hir::ImplicitSelfKind::None,
395 });
396
397 let header = self.generate_header_error();
398 let sig = hir::FnSig { decl, header, span };
399
400 let body_id = self.lower_body(|this| (&[], this.mk_expr(hir::ExprKind::Err(err), span)));
401 DelegationResults { generics, body_id, sig }
402 }
403
404 fn generate_header_error(&self) -> hir::FnHeader {
405 hir::FnHeader {
406 safety: hir::Safety::Safe.into(),
407 constness: hir::Constness::NotConst,
408 asyncness: hir::IsAsync::NotAsync,
409 abi: ExternAbi::Rust,
410 }
411 }
412
413 #[inline]
414 fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir> {
415 hir::Expr { hir_id: self.next_id(), kind, span }
416 }
417}
418
419struct SelfResolver<'a> {
420 resolver: &'a mut ResolverAstLowering,
421 path_id: NodeId,
422 self_param_id: NodeId,
423}
424
425impl<'a> SelfResolver<'a> {
426 fn try_replace_id(&mut self, id: NodeId) {
427 if let Some(res) = self.resolver.partial_res_map.get(&id)
428 && let Some(Res::Local(sig_id)) = res.full_res()
429 && sig_id == self.path_id
430 {
431 let new_res = PartialRes::new(Res::Local(self.self_param_id));
432 self.resolver.partial_res_map.insert(id, new_res);
433 }
434 }
435}
436
437impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a> {
438 fn visit_path(&mut self, path: &'ast Path, id: NodeId) {
439 self.try_replace_id(id);
440 visit::walk_path(self, path);
441 }
442
443 fn visit_path_segment(&mut self, seg: &'ast PathSegment) {
444 self.try_replace_id(seg.id);
445 visit::walk_path_segment(self, seg);
446 }
447}