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) -> Self {
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: &Self) -> 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() -> Self {
Self {
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(_) => {
347 Err(tcx.dcx().emit_err(UnresolvedDelegationCallee { span }))
348 }
349 TypeRelativeDelegationRes::Ambig(_) => {
350 Err(tcx.dcx().emit_err(AmbiguousDelegationToInherentImpl { span }))
351 }
352 },
353 None => Err(self.create_unresolved_error(def_id, span)),
354 }
355 }
356
357 fn check_for_cycles(&self, mut def_id: DefId, span: Span) -> Result<(), ErrorGuaranteed> {
358 let tcx = self.tcx();
359 let mut visited: FxHashSet<DefId> = Default::default();
360 let delegation_infos = &tcx.resolutions(()).delegation_infos;
361
362 loop {
363 visited.insert(def_id);
364
365 if let Some(local_id) = def_id.as_local()
369 && delegation_infos.contains_key(&local_id)
370 && let Ok(id) = self.resolve_delegation_sig(local_id, span)
371 {
372 def_id = id;
373 if visited.contains(&def_id) {
374 return Err(match visited.len() {
375 1 => tcx.dcx().emit_err(UnresolvedDelegationCallee { span }),
376 _ => tcx.dcx().emit_err(CycleInDelegationSignatureResolution { span }),
377 });
378 }
379 } else {
380 return Ok(());
381 }
382 }
383 }
384
385 fn check_block_soundness(
386 &self,
387 delegation: &Delegation,
388 sig_id: DefId,
389 is_method: bool,
390 param_count: usize,
391 ) -> Result<(bool, bool), ErrorGuaranteed> {
392 let tcx = self.tcx();
393 let should_generate_block = is_method
394 || #[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(sig_id) {
DefKind::Fn => true,
_ => false,
}matches!(tcx.def_kind(sig_id), DefKind::Fn)
395 || #[allow(non_exhaustive_omitted_patterns)] match delegation.source {
DelegationSource::Single => true,
_ => false,
}matches!(delegation.source, DelegationSource::Single);
396
397 let Some(block) = &delegation.body else { return Ok((should_generate_block, false)) };
398
399 if param_count == 0 && should_generate_block {
402 let err = DelegationBlockSpecifiedWhenNoParams { span: block.span };
403 return Err(tcx.dcx().emit_err(err));
404 }
405
406 struct DefinitionsFinder<'a, 'hir> {
407 resolver: &'a DelegationResolver<'a, 'hir>,
408 }
409
410 impl<'a> Visitor<'a> for DefinitionsFinder<'a, '_> {
411 type Result = ControlFlow<()>;
412
413 fn visit_id(&mut self, id: NodeId) -> Self::Result {
414 match self.resolver.is_definition(id) {
415 true => ControlFlow::Break(()),
416 false => ControlFlow::Continue(()),
417 }
418 }
419 }
420
421 let mut collector = DefinitionsFinder { resolver: self };
422
423 let contains_defs = collector.visit_block(block).is_break();
424
425 if should_generate_block || !contains_defs {
428 Ok((should_generate_block, contains_defs))
429 } else {
430 Err(tcx.dcx().emit_err(DelegationAttemptedBlockWithDefsDeletion { span: block.span }))
431 }
432 }
433
434 fn create_sig_mapping(
435 &self,
436 delegation: &Delegation,
437 span: Span,
438 should_generate_block: bool,
439 parent: LocalDefId,
440 sig: ty::FnSig<'tcx>,
441 contains_defs: bool,
442 ) -> Result<SigMapping, ErrorGuaranteed> {
443 let mut mapping = SigMapping::default();
444 if should_generate_block {
445 mapping.arguments_to_map.insert(0);
446 }
447
448 if self.can_perform_self_mapping(delegation, parent, span) {
449 struct SelfFinder;
452
453 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for SelfFinder {
454 type Result = ControlFlow<()>;
455
456 fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
457 match t.kind() {
458 ty::Adt(_, args) => {
459 if args
460 .iter()
461 .flat_map(|arg| arg.as_type())
462 .any(|type_arg| type_arg.is_self_param())
463 {
464 return ControlFlow::Break(());
465 }
466
467 t.super_visit_with(self)
468 }
469 ty::Ref(_, ref_t, _) => {
470 if ref_t.is_self_param() {
471 return ControlFlow::Break(());
472 }
473
474 t.super_visit_with(self)
475 }
476 _ => ControlFlow::Continue(()),
477 }
478 }
479 }
480
481 impl SelfFinder {
482 fn contains_self(t: Ty<'_>) -> bool {
483 t.is_self_param() || t.visit_with(&mut SelfFinder).is_break()
484 }
485 }
486
487 mapping.map_return = SelfFinder::contains_self(sig.output());
488
489 let arguments_to_map = sig
490 .inputs()
491 .iter()
492 .enumerate()
493 .skip(1) .filter_map(|(idx, ¶m)| SelfFinder::contains_self(param).then_some(idx));
495
496 mapping.arguments_to_map.extend(arguments_to_map);
497 }
498
499 if contains_defs && mapping.arguments_to_map.len() > 1 {
502 let err = DelegationAttemptedBlockWithDefsRelowering { span };
503 let err = self.tcx().dcx().emit_err(err);
504 return Err(err);
505 }
506
507 Ok(mapping)
508 }
509
510 fn can_perform_self_mapping(
511 &self,
512 delegation: &Delegation,
513 parent: LocalDefId,
514 span: Span,
515 ) -> bool {
516 if delegation.body.is_none() {
518 return false;
519 }
520
521 let tcx = self.tcx();
522
523 if !#[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(parent) {
DefKind::Impl { .. } => true,
_ => false,
}matches!(tcx.def_kind(parent), DefKind::Impl { .. }) {
534 return false;
535 }
536
537 let id = self
541 .get_call_path_res(delegation, span)
542 .ok()
543 .expect("invalid paths are filtered out earlier");
544
545 tcx.def_kind(id) == DefKind::AssocFn && tcx.def_kind(tcx.parent(id)) == DefKind::Trait
546 }
547}