rustc_ast_lowering/delegation/
resolution.rs1use std::ops::ControlFlow;
2
3use ast::visit::Visitor;
4use hir::def::DefKind;
5use rustc_ast::{self as ast, AssocItemKind, Delegation, DelegationSource, Item, ItemKind, NodeId};
6use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
7use rustc_data_structures::steal::Steal;
8use rustc_hir as hir;
9use rustc_middle::middle::resolve::{
10 self as mid_res, AstOwner, DelegationInherentFnKind, TypeRelativeDelegationRes,
11};
12use rustc_middle::ty::{
13 self as ty, AssocKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
14};
15use rustc_span::def_id::{DefId, LocalDefId};
16use rustc_span::{ErrorGuaranteed, Span};
17
18use crate::delegation::generics::GenericsGenerationResults;
19use crate::delegation::resolution::resolver::DelegationResolver;
20use crate::diagnostics::{
21 AmbiguousDelegationToInherentImpl, CycleInDelegationSignatureResolution,
22 DelegationAttemptedBlockWithDefsDeletion, DelegationAttemptedBlockWithDefsRelowering,
23 DelegationBlockSpecifiedWhenNoParams, UnresolvedDelegationCallee,
24};
25
26pub(crate) fn resolve_type_relative_delegations(
36 tcx: TyCtxt<'_>,
37 _: (),
38) -> FxIndexMap<LocalDefId, TypeRelativeDelegationRes> {
39 let ast_index = tcx.index_ast(());
40 let resolutions = tcx.resolutions(());
41
42 let infos = &resolutions.delegation_infos;
43 let inh_fns = &resolutions.delegation_inherent_fn_map;
44
45 let mut type_relative_resolutions: FxIndexMap<LocalDefId, TypeRelativeDelegationRes> =
46 Default::default();
47
48 for (&def_id, res) in infos {
49 match res.resolution {
50 mid_res::DelegationResolution::Error(..) | mid_res::DelegationResolution::Full(_) => {
51 continue;
52 }
53 mid_res::DelegationResolution::Partial
55 | mid_res::DelegationResolution::PartialCall(_) => {
56 let Some(r_and_owner) = ast_index.get(def_id).map(Steal::borrow) else {
57 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("ast index must contain delegations")));
};unreachable!("ast index must contain delegations");
58 };
59
60 let (r, owner) = &*r_and_owner;
61
62 let delegation = match owner {
63 AstOwner::Item(Item { kind: ItemKind::Delegation(d), .. })
64 | AstOwner::TraitItem(Item { kind: AssocItemKind::Delegation(d), .. })
65 | AstOwner::ImplItem(Item { kind: AssocItemKind::Delegation(d), .. }) => d,
66 _ => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("we are processing only delegations")));
}unreachable!("we are processing only delegations"),
67 };
68
69 let res = r.partial_res_map.get(&delegation.id);
70 let res = res.and_then(|res| res.base_res().opt_def_id());
71 let ident = delegation.path.segments.last().map(|s| s.ident);
72
73 let span = delegation.last_segment_span();
74
75 let ambig_error_res = || {
76 TypeRelativeDelegationRes::Ambig(
77 tcx.dcx().span_delayed_bug(span, "ambiguous delegation to inherent impl"),
78 )
79 };
80
81 let default_error_res =
82 || {
83 TypeRelativeDelegationRes::Error(tcx.dcx().span_delayed_bug(
84 span,
85 "failed to resolve delegation to inherent impl",
86 ))
87 };
88
89 let res = if let Some(res) = res
90 && let Some(ident) = ident
91 {
92 match res.as_local() {
93 Some(local_def_id) => {
94 let res = inh_fns.get(&local_def_id).and_then(|map| map.get(&ident));
95
96 match res {
97 Some(res) => match res {
98 DelegationInherentFnKind::Ambig => ambig_error_res(),
99 DelegationInherentFnKind::Single(res) => {
100 TypeRelativeDelegationRes::Ok(res.to_def_id())
101 }
102 },
103 _ => default_error_res(),
104 }
105 }
106 None => {
107 let mut sig_res = None;
108 'inh_loop: for inh_impl_id in tcx.inherent_impls(res) {
109 let assoc_items = tcx.associated_items(*inh_impl_id);
110
111 let mut candidates = assoc_items
113 .filter_by_name_unhygienic(ident.name)
114 .filter(|it| #[allow(non_exhaustive_omitted_patterns)] match it.kind {
AssocKind::Fn { .. } => true,
_ => false,
}matches!(it.kind, AssocKind::Fn { .. }));
115
116 while let Some(candidate) = candidates.next() {
117 if sig_res.is_some() {
118 sig_res = Some(ambig_error_res());
119 break 'inh_loop;
120 } else {
121 sig_res =
122 Some(TypeRelativeDelegationRes::Ok(candidate.def_id));
123 }
124 }
125 }
126
127 sig_res.unwrap_or_else(default_error_res)
128 }
129 }
130 } else {
131 default_error_res()
132 };
133
134 type_relative_resolutions.insert(def_id, res);
135 }
136 }
137 }
138
139 type_relative_resolutions
140}
141
142#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ParamInfo {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "ParamInfo",
"param_count", &self.param_count, "c_variadic", &self.c_variadic,
"splatted", &&self.splatted)
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ParamInfo { }
#[automatically_derived]
impl ::core::clone::Clone for ParamInfo {
#[inline]
fn clone(&self) -> ParamInfo {
let _: ::core::clone::AssertParamIsClone<usize>;
let _: ::core::clone::AssertParamIsClone<bool>;
let _: ::core::clone::AssertParamIsClone<Option<u8>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ParamInfo { }Copy, #[automatically_derived]
impl ::core::cmp::Eq for ParamInfo {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<usize>;
let _: ::core::cmp::AssertParamIsEq<bool>;
let _: ::core::cmp::AssertParamIsEq<Option<u8>>;
}
}Eq, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ParamInfo { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ParamInfo {
#[inline]
fn eq(&self, other: &ParamInfo) -> bool {
self.c_variadic == other.c_variadic &&
self.param_count == other.param_count &&
self.splatted == other.splatted
}
}PartialEq)]
144pub(super) struct ParamInfo {
145 pub param_count: usize,
147
148 pub c_variadic: bool,
150
151 pub splatted: Option<u8>,
153}
154
155#[derive(#[automatically_derived]
impl ::core::default::Default for SigMapping {
#[inline]
fn default() -> SigMapping {
SigMapping {
map_return: ::core::default::Default::default(),
arguments_to_map: ::core::default::Default::default(),
}
}
}Default, #[automatically_derived]
impl ::core::fmt::Debug for SigMapping {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "SigMapping",
"map_return", &self.map_return, "arguments_to_map",
&&self.arguments_to_map)
}
}Debug)]
156pub(super) struct SigMapping {
157 pub map_return: bool,
158 pub arguments_to_map: FxIndexSet<usize>,
159}
160
161pub(super) struct DelegationResolution {
162 pub sig_id: DefId,
163 pub is_method: bool,
164 pub param_info: ParamInfo,
165 pub span: Span,
166 pub call_path_res: DefId,
167 pub source: DelegationSource,
168 pub parent: LocalDefId,
169 pub sig_mapping: SigMapping,
170}
171
172pub(super) mod resolver {
173 use rustc_ast::NodeId;
174 use rustc_hir::def_id::{DefId, LocalDefId};
175 use rustc_middle::ty::TyCtxt;
176 use rustc_span::ErrorGuaranteed;
177
178 use crate::LoweringContext;
179
180 pub(crate) struct DelegationResolver<'a, 'hir>(&'a LoweringContext<'a, 'hir>);
184
185 impl<'a, 'tcx> DelegationResolver<'a, 'tcx> {
186 pub(crate) fn new(ctx: &'a LoweringContext<'a, 'tcx>) -> Self {
187 DelegationResolver(ctx)
188 }
189
190 #[inline]
191 pub(crate) fn tcx(&self) -> TyCtxt<'tcx> {
192 self.0.tcx
193 }
194
195 #[inline]
196 pub(crate) fn owner_id(&self) -> LocalDefId {
197 self.0.curr_owner.owner.def_id
198 }
199
200 #[inline]
213 pub(crate) fn is_definition(&self, id: NodeId) -> bool {
214 self.0.resolver.owners.contains_key(&id)
215 || self.0.curr_owner.owner.node_id_to_def_id.contains_key(&id)
216 }
217
218 #[inline]
219 pub(crate) fn get_resolution_id(&self, id: NodeId) -> Result<DefId, ErrorGuaranteed> {
220 self.0.get_partial_res(id).and_then(|r| r.expect_full_res().opt_def_id()).ok_or_else(
221 || self.tcx().dcx().delayed_bug(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("failed to resolve node {0:?}", id))
})format!("failed to resolve node {id:?}")),
222 )
223 }
224 }
225}
226
227impl<'tcx> DelegationResolver<'_, 'tcx> {
228 pub(super) fn resolve_delegation(
229 &self,
230 delegation: &Delegation,
231 span: Span,
232 ) -> Result<(DelegationResolution, GenericsGenerationResults<'tcx>), ErrorGuaranteed> {
233 let tcx = self.tcx();
234 let def_id = self.owner_id();
235
236 let sig_id = self.resolve_delegation_sig(def_id, span)?;
239
240 let create_invalid_path_error =
241 || tcx.dcx().span_delayed_bug(span, "invalid delegation path");
242
243 match &delegation.path.segments[..] {
244 [] => return Err(create_invalid_path_error()),
245 [child] => {
246 let res = self.get_resolution_id(child.id)?;
247 if tcx.def_kind(res) != DefKind::Fn {
248 return Err(create_invalid_path_error());
249 }
250 }
251 [.., parent, _] => {
252 let child_res = self.get_call_path_res(delegation, span)?;
253 let parent_res = self.get_resolution_id(parent.id)?;
254
255 match (tcx.def_kind(child_res), tcx.def_kind(parent_res)) {
256 (DefKind::Fn, DefKind::Mod) => {}
257 (DefKind::AssocFn, DefKind::Trait | DefKind::Struct | DefKind::Enum) => {}
258 _ => return Err(create_invalid_path_error()),
259 }
260 }
261 }
262
263 self.check_for_cycles(sig_id, span)?;
264
265 let is_method = tcx.is_method(sig_id);
266 let sig = tcx.fn_sig(sig_id).skip_binder().skip_binder();
267 let param_count = sig.inputs().len() + usize::from(sig.c_variadic());
268 let parent = tcx.local_parent(def_id);
269
270 let (should_generate_block, contains_defs) =
271 self.check_block_soundness(delegation, sig_id, is_method, param_count)?;
272
273 let res = DelegationResolution {
274 is_method,
275 span,
276 sig_id,
277 parent,
278 param_info: ParamInfo { param_count, c_variadic: sig.c_variadic(), splatted: None },
280 source: delegation.source,
281 call_path_res: self.get_call_path_res(delegation, span)?,
282 sig_mapping: self.create_sig_mapping(
283 delegation,
284 span,
285 should_generate_block,
286 parent,
287 sig,
288 contains_defs,
289 )?,
290 };
291
292 Ok((res, self.resolve_and_generate_generics(delegation, sig_id, span)?))
293 }
294
295 fn get_call_path_res(
296 &self,
297 delegation: &Delegation,
298 span: Span,
299 ) -> Result<DefId, ErrorGuaranteed> {
300 let def_id = self.owner_id();
301
302 match self.tcx().resolutions(()).delegation_infos[&def_id].resolution {
303 mid_res::DelegationResolution::Full(_) => self.get_resolution_id(delegation.id),
304 mid_res::DelegationResolution::Partial
305 | mid_res::DelegationResolution::PartialCall(_) => {
306 self.resolve_type_relative_delegation_sig(def_id, span)
307 }
308 mid_res::DelegationResolution::Error(err) => Err(err),
309 }
310 }
311
312 fn resolve_delegation_sig(
313 &self,
314 def_id: LocalDefId,
315 span: Span,
316 ) -> Result<DefId, ErrorGuaranteed> {
317 let tcx = self.tcx();
318
319 match tcx.resolutions(()).delegation_infos.get(&def_id) {
320 Some(res) => match res.resolution {
321 mid_res::DelegationResolution::Error(err) => Err(err),
322 mid_res::DelegationResolution::Full(def_id)
323 | mid_res::DelegationResolution::PartialCall(def_id) => Ok(def_id),
324 mid_res::DelegationResolution::Partial => {
325 self.resolve_type_relative_delegation_sig(def_id, span)
326 }
327 },
328 None => Err(self.create_unresolved_error(def_id, span)),
329 }
330 }
331
332 fn create_unresolved_error(&self, def_id: LocalDefId, span: Span) -> ErrorGuaranteed {
333 self.tcx().dcx().span_delayed_bug(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unresolved delegation {0:?}",
def_id))
})format!("unresolved delegation {def_id:?}"))
334 }
335
336 fn resolve_type_relative_delegation_sig(
337 &self,
338 def_id: LocalDefId,
339 span: Span,
340 ) -> Result<DefId, ErrorGuaranteed> {
341 let tcx = self.tcx();
342
343 match tcx.resolve_type_relative_delegations(()).get(&def_id) {
344 Some(res) => match *res {
345 TypeRelativeDelegationRes::Ok(sig_id) => Ok(sig_id),
346 TypeRelativeDelegationRes::Error(err) => Err(err),
347 TypeRelativeDelegationRes::Ambig(_) => {
348 Err(tcx.dcx().emit_err(AmbiguousDelegationToInherentImpl { span }))
349 }
350 },
351 None => Err(self.create_unresolved_error(def_id, span)),
352 }
353 }
354
355 fn check_for_cycles(&self, mut def_id: DefId, span: Span) -> Result<(), ErrorGuaranteed> {
356 let tcx = self.tcx();
357 let mut visited: FxHashSet<DefId> = Default::default();
358 let delegation_infos = &tcx.resolutions(()).delegation_infos;
359
360 loop {
361 visited.insert(def_id);
362
363 if let Some(local_id) = def_id.as_local()
367 && delegation_infos.contains_key(&local_id)
368 && let Ok(id) = self.resolve_delegation_sig(local_id, span)
369 {
370 def_id = id;
371 if visited.contains(&def_id) {
372 return Err(match visited.len() {
373 1 => tcx.dcx().emit_err(UnresolvedDelegationCallee { span }),
374 _ => tcx.dcx().emit_err(CycleInDelegationSignatureResolution { span }),
375 });
376 }
377 } else {
378 return Ok(());
379 }
380 }
381 }
382
383 fn check_block_soundness(
384 &self,
385 delegation: &Delegation,
386 sig_id: DefId,
387 is_method: bool,
388 param_count: usize,
389 ) -> Result<(bool, bool), ErrorGuaranteed> {
390 let tcx = self.tcx();
391 let should_generate_block = is_method
392 || #[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(sig_id) {
DefKind::Fn => true,
_ => false,
}matches!(tcx.def_kind(sig_id), DefKind::Fn)
393 || #[allow(non_exhaustive_omitted_patterns)] match delegation.source {
DelegationSource::Single => true,
_ => false,
}matches!(delegation.source, DelegationSource::Single);
394
395 let Some(block) = &delegation.body else { return Ok((should_generate_block, false)) };
396
397 if param_count == 0 && should_generate_block {
400 let err = DelegationBlockSpecifiedWhenNoParams { span: block.span };
401 return Err(tcx.dcx().emit_err(err));
402 }
403
404 struct DefinitionsFinder<'a, 'hir> {
405 resolver: &'a DelegationResolver<'a, 'hir>,
406 }
407
408 impl<'a> Visitor<'a> for DefinitionsFinder<'a, '_> {
409 type Result = ControlFlow<()>;
410
411 fn visit_id(&mut self, id: NodeId) -> Self::Result {
412 match self.resolver.is_definition(id) {
413 true => ControlFlow::Break(()),
414 false => ControlFlow::Continue(()),
415 }
416 }
417 }
418
419 let mut collector = DefinitionsFinder { resolver: self };
420
421 let contains_defs = collector.visit_block(block).is_break();
422
423 if should_generate_block || !contains_defs {
426 Ok((should_generate_block, contains_defs))
427 } else {
428 Err(tcx.dcx().emit_err(DelegationAttemptedBlockWithDefsDeletion { span: block.span }))
429 }
430 }
431
432 fn create_sig_mapping(
433 &self,
434 delegation: &Delegation,
435 span: Span,
436 should_generate_block: bool,
437 parent: LocalDefId,
438 sig: ty::FnSig<'tcx>,
439 contains_defs: bool,
440 ) -> Result<SigMapping, ErrorGuaranteed> {
441 let mut mapping = SigMapping::default();
442 if should_generate_block {
443 mapping.arguments_to_map.insert(0);
444 }
445
446 if self.can_perform_self_mapping(delegation, parent, span) {
447 struct SelfFinder;
450
451 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for SelfFinder {
452 type Result = ControlFlow<()>;
453
454 fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
455 match t.kind() {
456 ty::Adt(_, args) => {
457 if args
458 .iter()
459 .flat_map(|arg| arg.as_type())
460 .any(|type_arg| type_arg.is_self_param())
461 {
462 return ControlFlow::Break(());
463 }
464
465 t.super_visit_with(self)
466 }
467 ty::Ref(_, ref_t, _) => {
468 if ref_t.is_self_param() {
469 return ControlFlow::Break(());
470 }
471
472 t.super_visit_with(self)
473 }
474 _ => ControlFlow::Continue(()),
475 }
476 }
477 }
478
479 impl SelfFinder {
480 fn contains_self(t: Ty<'_>) -> bool {
481 t.is_self_param() || t.visit_with(&mut SelfFinder).is_break()
482 }
483 }
484
485 mapping.map_return = SelfFinder::contains_self(sig.output());
486
487 let arguments_to_map = sig
488 .inputs()
489 .iter()
490 .enumerate()
491 .skip(1) .filter_map(|(idx, ¶m)| SelfFinder::contains_self(param).then_some(idx));
493
494 mapping.arguments_to_map.extend(arguments_to_map);
495 }
496
497 if contains_defs && mapping.arguments_to_map.len() > 1 {
500 let err = DelegationAttemptedBlockWithDefsRelowering { span };
501 let err = self.tcx().dcx().emit_err(err);
502 return Err(err);
503 }
504
505 Ok(mapping)
506 }
507
508 fn can_perform_self_mapping(
509 &self,
510 delegation: &Delegation,
511 parent: LocalDefId,
512 span: Span,
513 ) -> bool {
514 if delegation.body.is_none() {
516 return false;
517 }
518
519 let tcx = self.tcx();
520
521 if !#[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(parent) {
DefKind::Impl { .. } => true,
_ => false,
}matches!(tcx.def_kind(parent), DefKind::Impl { .. }) {
532 return false;
533 }
534
535 let id = self
539 .get_call_path_res(delegation, span)
540 .ok()
541 .expect("invalid paths are filtered out earlier");
542
543 tcx.def_kind(id) == DefKind::AssocFn && tcx.def_kind(tcx.parent(id)) == DefKind::Trait
544 }
545}