1use std::ops::Deref;
2
3use rustc_hir as hir;
4use rustc_hir::GenericArg;
5use rustc_hir::def_id::DefId;
6use rustc_hir_analysis::hir_ty_lowering::generics::{
7 check_generic_arg_count_for_call, lower_generic_args,
8};
9use rustc_hir_analysis::hir_ty_lowering::{
10 FeedConstTy, GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason,
11};
12use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
13use rustc_lint::builtin::SUPERTRAIT_ITEM_SHADOWING_USAGE;
14use rustc_middle::traits::ObligationCauseCode;
15use rustc_middle::ty::adjustment::{
16 Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
17};
18use rustc_middle::ty::{
19 self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
20 TypeVisitableExt, UserArgs,
21};
22use rustc_middle::{bug, span_bug};
23use rustc_span::{DUMMY_SP, Span};
24use rustc_trait_selection::traits;
25use tracing::debug;
26
27use super::{MethodCallee, probe};
28use crate::errors::{SupertraitItemShadowee, SupertraitItemShadower, SupertraitItemShadowing};
29use crate::{FnCtxt, callee};
30
31struct ConfirmContext<'a, 'tcx> {
32 fcx: &'a FnCtxt<'a, 'tcx>,
33 span: Span,
34 self_expr: &'tcx hir::Expr<'tcx>,
35 call_expr: &'tcx hir::Expr<'tcx>,
36 skip_record_for_diagnostics: bool,
37}
38
39impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> {
40 type Target = FnCtxt<'a, 'tcx>;
41 fn deref(&self) -> &Self::Target {
42 self.fcx
43 }
44}
45
46#[derive(Debug)]
47pub(crate) struct ConfirmResult<'tcx> {
48 pub callee: MethodCallee<'tcx>,
49 pub illegal_sized_bound: Option<Span>,
50}
51
52impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
53 pub(crate) fn confirm_method(
54 &self,
55 span: Span,
56 self_expr: &'tcx hir::Expr<'tcx>,
57 call_expr: &'tcx hir::Expr<'tcx>,
58 unadjusted_self_ty: Ty<'tcx>,
59 pick: &probe::Pick<'tcx>,
60 segment: &'tcx hir::PathSegment<'tcx>,
61 ) -> ConfirmResult<'tcx> {
62 debug!(
63 "confirm(unadjusted_self_ty={:?}, pick={:?}, generic_args={:?})",
64 unadjusted_self_ty, pick, segment.args,
65 );
66
67 let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
68 confirm_cx.confirm(unadjusted_self_ty, pick, segment)
69 }
70
71 pub(crate) fn confirm_method_for_diagnostic(
72 &self,
73 span: Span,
74 self_expr: &'tcx hir::Expr<'tcx>,
75 call_expr: &'tcx hir::Expr<'tcx>,
76 unadjusted_self_ty: Ty<'tcx>,
77 pick: &probe::Pick<'tcx>,
78 segment: &hir::PathSegment<'tcx>,
79 ) -> ConfirmResult<'tcx> {
80 let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
81 confirm_cx.skip_record_for_diagnostics = true;
82 confirm_cx.confirm(unadjusted_self_ty, pick, segment)
83 }
84}
85
86impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
87 fn new(
88 fcx: &'a FnCtxt<'a, 'tcx>,
89 span: Span,
90 self_expr: &'tcx hir::Expr<'tcx>,
91 call_expr: &'tcx hir::Expr<'tcx>,
92 ) -> ConfirmContext<'a, 'tcx> {
93 ConfirmContext { fcx, span, self_expr, call_expr, skip_record_for_diagnostics: false }
94 }
95
96 fn confirm(
97 &mut self,
98 unadjusted_self_ty: Ty<'tcx>,
99 pick: &probe::Pick<'tcx>,
100 segment: &hir::PathSegment<'tcx>,
101 ) -> ConfirmResult<'tcx> {
102 let self_ty = self.adjust_self_ty(unadjusted_self_ty, pick);
104
105 let rcvr_args = self.fresh_receiver_args(self_ty, pick);
107 let all_args = self.instantiate_method_args(pick, segment, rcvr_args);
108
109 debug!("rcvr_args={rcvr_args:?}, all_args={all_args:?}");
110
111 let (method_sig, method_predicates) = self.instantiate_method_sig(pick, all_args);
113
114 let filler_args = rcvr_args
123 .extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def));
124 let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
125 self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_args),
126 );
127
128 let method_sig_rcvr = self.normalize(self.span, method_sig.inputs()[0]);
135 debug!(
136 "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}",
137 self_ty, method_sig_rcvr, method_sig, method_predicates
138 );
139 self.unify_receivers(self_ty, method_sig_rcvr, pick);
140
141 let (method_sig, method_predicates) =
142 self.normalize(self.span, (method_sig, method_predicates));
143 let method_sig = ty::Binder::dummy(method_sig);
144
145 self.check_for_illegal_method_calls(pick);
147
148 self.lint_shadowed_supertrait_items(pick, segment);
150
151 if illegal_sized_bound.is_none() {
155 self.add_obligations(
156 Ty::new_fn_ptr(self.tcx, method_sig),
157 all_args,
158 method_predicates,
159 pick.item.def_id,
160 );
161 }
162
163 let callee = MethodCallee {
165 def_id: pick.item.def_id,
166 args: all_args,
167 sig: method_sig.skip_binder(),
168 };
169 ConfirmResult { callee, illegal_sized_bound }
170 }
171
172 fn adjust_self_ty(
176 &mut self,
177 unadjusted_self_ty: Ty<'tcx>,
178 pick: &probe::Pick<'tcx>,
179 ) -> Ty<'tcx> {
180 let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty);
183 let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
184 return Ty::new_error_with_message(
185 self.tcx,
186 DUMMY_SP,
187 format!("failed autoderef {}", pick.autoderefs),
188 );
189 };
190 assert_eq!(n, pick.autoderefs);
191
192 let mut adjustments = self.adjust_steps(&autoderef);
193 let mut target = self.structurally_resolve_type(autoderef.span(), ty);
194
195 match pick.autoref_or_ptr_adjustment {
196 Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
197 let region = self.next_region_var(infer::Autoref(self.span));
198 let base_ty = target;
200
201 target = Ty::new_ref(self.tcx, region, target, mutbl);
202
203 let mutbl = AutoBorrowMutability::new(mutbl, AllowTwoPhase::Yes);
206
207 adjustments
208 .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target });
209
210 if unsize {
211 let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
212 Ty::new_slice(self.tcx, *elem_ty)
213 } else {
214 bug!(
215 "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
216 base_ty
217 )
218 };
219 target = Ty::new_ref(self.tcx, region, unsized_ty, mutbl.into());
220 adjustments.push(Adjustment {
221 kind: Adjust::Pointer(PointerCoercion::Unsize),
222 target,
223 });
224 }
225 }
226 Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
227 target = match target.kind() {
228 &ty::RawPtr(ty, mutbl) => {
229 assert!(mutbl.is_mut());
230 Ty::new_imm_ptr(self.tcx, ty)
231 }
232 other => panic!("Cannot adjust receiver type {other:?} to const ptr"),
233 };
234
235 adjustments.push(Adjustment {
236 kind: Adjust::Pointer(PointerCoercion::MutToConstPointer),
237 target,
238 });
239 }
240
241 Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
242 let region = self.next_region_var(infer::Autoref(self.span));
243
244 target = match target.kind() {
245 ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
246 let inner_ty = match args[0].expect_ty().kind() {
247 ty::Ref(_, ty, _) => *ty,
248 _ => bug!("Expected a reference type for argument to Pin"),
249 };
250 Ty::new_pinned_ref(self.tcx, region, inner_ty, mutbl)
251 }
252 _ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"),
253 };
254
255 adjustments.push(Adjustment { kind: Adjust::ReborrowPin(mutbl), target });
256 }
257 None => {}
258 }
259
260 self.register_predicates(autoderef.into_obligations());
261
262 if !self.skip_record_for_diagnostics {
264 self.apply_adjustments(self.self_expr, adjustments);
265 }
266
267 target
268 }
269
270 fn fresh_receiver_args(
277 &mut self,
278 self_ty: Ty<'tcx>,
279 pick: &probe::Pick<'tcx>,
280 ) -> GenericArgsRef<'tcx> {
281 match pick.kind {
282 probe::InherentImplPick => {
283 let impl_def_id = pick.item.container_id(self.tcx);
284 assert!(
285 self.tcx.impl_trait_ref(impl_def_id).is_none(),
286 "impl {impl_def_id:?} is not an inherent impl"
287 );
288 self.fresh_args_for_item(self.span, impl_def_id)
289 }
290
291 probe::ObjectPick => {
292 let trait_def_id = pick.item.container_id(self.tcx);
293
294 if !self.tcx.is_dyn_compatible(trait_def_id) {
299 return ty::GenericArgs::extend_with_error(self.tcx, trait_def_id, &[]);
300 }
301
302 if self_ty.references_error() {
309 return ty::GenericArgs::extend_with_error(self.tcx, trait_def_id, &[]);
310 }
311
312 self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
313 let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty);
324 let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
325 let upcast_trait_ref =
326 this.instantiate_binder_with_fresh_vars(upcast_poly_trait_ref);
327 debug!(
328 "original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
329 original_poly_trait_ref, upcast_trait_ref, trait_def_id
330 );
331 upcast_trait_ref.args
332 })
333 }
334
335 probe::TraitPick => {
336 let trait_def_id = pick.item.container_id(self.tcx);
337
338 self.fresh_args_for_item(self.span, trait_def_id)
344 }
345
346 probe::WhereClausePick(poly_trait_ref) => {
347 self.instantiate_binder_with_fresh_vars(poly_trait_ref).args
350 }
351 }
352 }
353
354 fn extract_existential_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R
355 where
356 F: FnMut(&mut ConfirmContext<'a, 'tcx>, Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>) -> R,
357 {
358 let mut autoderef = self.fcx.autoderef(self.span, self_ty);
364
365 if self.tcx.features().arbitrary_self_types()
368 || self.tcx.features().arbitrary_self_types_pointers()
369 {
370 autoderef = autoderef.use_receiver_trait();
371 }
372
373 autoderef
374 .include_raw_pointers()
375 .find_map(|(ty, _)| match ty.kind() {
376 ty::Dynamic(data, ..) => Some(closure(
377 self,
378 ty,
379 data.principal().unwrap_or_else(|| {
380 span_bug!(self.span, "calling trait method on empty object?")
381 }),
382 )),
383 _ => None,
384 })
385 .unwrap_or_else(|| {
386 span_bug!(
387 self.span,
388 "self-type `{}` for ObjectPick never dereferenced to an object",
389 self_ty
390 )
391 })
392 }
393
394 fn instantiate_method_args(
395 &mut self,
396 pick: &probe::Pick<'tcx>,
397 seg: &hir::PathSegment<'tcx>,
398 parent_args: GenericArgsRef<'tcx>,
399 ) -> GenericArgsRef<'tcx> {
400 let generics = self.tcx.generics_of(pick.item.def_id);
404
405 let arg_count_correct = check_generic_arg_count_for_call(
406 self.fcx,
407 pick.item.def_id,
408 generics,
409 seg,
410 IsMethodCall::Yes,
411 );
412
413 assert_eq!(generics.parent_count, parent_args.len());
416
417 struct GenericArgsCtxt<'a, 'tcx> {
418 cfcx: &'a ConfirmContext<'a, 'tcx>,
419 pick: &'a probe::Pick<'tcx>,
420 seg: &'a hir::PathSegment<'tcx>,
421 }
422 impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for GenericArgsCtxt<'a, 'tcx> {
423 fn args_for_def_id(
424 &mut self,
425 def_id: DefId,
426 ) -> (Option<&'a hir::GenericArgs<'tcx>>, bool) {
427 if def_id == self.pick.item.def_id {
428 if let Some(data) = self.seg.args {
429 return (Some(data), false);
430 }
431 }
432 (None, false)
433 }
434
435 fn provided_kind(
436 &mut self,
437 preceding_args: &[ty::GenericArg<'tcx>],
438 param: &ty::GenericParamDef,
439 arg: &GenericArg<'tcx>,
440 ) -> ty::GenericArg<'tcx> {
441 match (¶m.kind, arg) {
442 (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self
443 .cfcx
444 .fcx
445 .lowerer()
446 .lower_lifetime(lt, RegionInferReason::Param(param))
447 .into(),
448 (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
449 self.cfcx.lower_ty(ty.as_unambig_ty()).raw.into()
451 }
452 (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
453 self.cfcx.lower_ty(&inf.to_ty()).raw.into()
454 }
455 (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
456 .cfcx
457 .lower_const_arg(
459 ct.as_unambig_ct(),
460 FeedConstTy::Param(param.def_id, preceding_args),
461 )
462 .into(),
463 (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
464 self.cfcx.ct_infer(Some(param), inf.span).into()
465 }
466 (kind, arg) => {
467 bug!("mismatched method arg kind {kind:?} in turbofish: {arg:?}")
468 }
469 }
470 }
471
472 fn inferred_kind(
473 &mut self,
474 _preceding_args: &[ty::GenericArg<'tcx>],
475 param: &ty::GenericParamDef,
476 _infer_args: bool,
477 ) -> ty::GenericArg<'tcx> {
478 self.cfcx.var_for_def(self.cfcx.span, param)
479 }
480 }
481
482 let args = lower_generic_args(
483 self.fcx,
484 pick.item.def_id,
485 parent_args,
486 false,
487 None,
488 &arg_count_correct,
489 &mut GenericArgsCtxt { cfcx: self, pick, seg },
490 );
491
492 if !args.is_empty() && !generics.is_own_empty() {
507 let user_type_annotation = self.probe(|_| {
508 let user_args = UserArgs {
509 args: GenericArgs::for_item(self.tcx, pick.item.def_id, |param, _| {
510 let i = param.index as usize;
511 if i < generics.parent_count {
512 self.fcx.var_for_def(DUMMY_SP, param)
513 } else {
514 args[i]
515 }
516 }),
517 user_self_ty: None, };
519
520 self.fcx.canonicalize_user_type_annotation(ty::UserType::new(
521 ty::UserTypeKind::TypeOf(pick.item.def_id, user_args),
522 ))
523 });
524
525 debug!("instantiate_method_args: user_type_annotation={:?}", user_type_annotation);
526
527 if !self.skip_record_for_diagnostics {
528 self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation);
529 }
530 }
531
532 self.normalize(self.span, args)
533 }
534
535 fn unify_receivers(
536 &mut self,
537 self_ty: Ty<'tcx>,
538 method_self_ty: Ty<'tcx>,
539 pick: &probe::Pick<'tcx>,
540 ) {
541 debug!(
542 "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}",
543 self_ty, method_self_ty, self.span, pick
544 );
545 let cause = self.cause(self.self_expr.span, ObligationCauseCode::Misc);
546 match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::Yes, method_self_ty, self_ty) {
547 Ok(InferOk { obligations, value: () }) => {
548 self.register_predicates(obligations);
549 }
550 Err(terr) => {
551 if self.tcx.features().arbitrary_self_types() {
552 self.err_ctxt()
553 .report_mismatched_types(
554 &cause,
555 self.param_env,
556 method_self_ty,
557 self_ty,
558 terr,
559 )
560 .emit();
561 } else {
562 self.dcx().span_delayed_bug(
565 cause.span,
566 format!("{self_ty} was a subtype of {method_self_ty} but now is not?"),
567 );
568 }
569 }
570 }
571 }
572
573 fn instantiate_method_sig(
577 &mut self,
578 pick: &probe::Pick<'tcx>,
579 all_args: GenericArgsRef<'tcx>,
580 ) -> (ty::FnSig<'tcx>, ty::InstantiatedPredicates<'tcx>) {
581 debug!("instantiate_method_sig(pick={:?}, all_args={:?})", pick, all_args);
582
583 let def_id = pick.item.def_id;
587 let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args);
588
589 debug!("method_predicates after instantitation = {:?}", method_predicates);
590
591 let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, all_args);
592 debug!("type scheme instantiated, sig={:?}", sig);
593
594 let sig = self.instantiate_binder_with_fresh_vars(sig);
595 debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
596
597 (sig, method_predicates)
598 }
599
600 fn add_obligations(
601 &mut self,
602 fty: Ty<'tcx>,
603 all_args: GenericArgsRef<'tcx>,
604 method_predicates: ty::InstantiatedPredicates<'tcx>,
605 def_id: DefId,
606 ) {
607 debug!(
608 "add_obligations: fty={:?} all_args={:?} method_predicates={:?} def_id={:?}",
609 fty, all_args, method_predicates, def_id
610 );
611
612 for obligation in traits::predicates_for_generics(
616 |idx, span| {
617 let code = ObligationCauseCode::WhereClauseInExpr(
618 def_id,
619 span,
620 self.call_expr.hir_id,
621 idx,
622 );
623 self.cause(self.span, code)
624 },
625 self.param_env,
626 method_predicates,
627 ) {
628 self.register_predicate(obligation);
629 }
630
631 self.add_wf_bounds(all_args, self.call_expr.span);
634
635 self.register_wf_obligation(fty.into(), self.span, ObligationCauseCode::WellFormed(None));
639 }
640
641 fn predicates_require_illegal_sized_bound(
645 &self,
646 predicates: ty::InstantiatedPredicates<'tcx>,
647 ) -> Option<Span> {
648 let sized_def_id = self.tcx.lang_items().sized_trait()?;
649
650 traits::elaborate(self.tcx, predicates.predicates.iter().copied())
651 .filter_map(|pred| match pred.kind().skip_binder() {
653 ty::ClauseKind::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
654 let span = predicates
655 .iter()
656 .find_map(|(p, span)| if p == pred { Some(span) } else { None })
657 .unwrap_or(DUMMY_SP);
658 Some((trait_pred, span))
659 }
660 _ => None,
661 })
662 .find_map(|(trait_pred, span)| match trait_pred.self_ty().kind() {
663 ty::Dynamic(..) => Some(span),
664 _ => None,
665 })
666 }
667
668 fn check_for_illegal_method_calls(&self, pick: &probe::Pick<'_>) {
669 if let Some(trait_def_id) = pick.item.trait_container(self.tcx) {
671 if let Err(e) = callee::check_legal_trait_for_method_call(
672 self.tcx,
673 self.span,
674 Some(self.self_expr.span),
675 self.call_expr.span,
676 trait_def_id,
677 self.body_id.to_def_id(),
678 ) {
679 self.set_tainted_by_errors(e);
680 }
681 }
682 }
683
684 fn lint_shadowed_supertrait_items(
685 &self,
686 pick: &probe::Pick<'_>,
687 segment: &hir::PathSegment<'tcx>,
688 ) {
689 if pick.shadowed_candidates.is_empty() {
690 return;
691 }
692
693 let shadower_span = self.tcx.def_span(pick.item.def_id);
694 let subtrait = self.tcx.item_name(pick.item.trait_container(self.tcx).unwrap());
695 let shadower = SupertraitItemShadower { span: shadower_span, subtrait };
696
697 let shadowee = if let [shadowee] = &pick.shadowed_candidates[..] {
698 let shadowee_span = self.tcx.def_span(shadowee.def_id);
699 let supertrait = self.tcx.item_name(shadowee.trait_container(self.tcx).unwrap());
700 SupertraitItemShadowee::Labeled { span: shadowee_span, supertrait }
701 } else {
702 let (traits, spans): (Vec<_>, Vec<_>) = pick
703 .shadowed_candidates
704 .iter()
705 .map(|item| {
706 (
707 self.tcx.item_name(item.trait_container(self.tcx).unwrap()),
708 self.tcx.def_span(item.def_id),
709 )
710 })
711 .unzip();
712 SupertraitItemShadowee::Several { traits: traits.into(), spans: spans.into() }
713 };
714
715 self.tcx.emit_node_span_lint(
716 SUPERTRAIT_ITEM_SHADOWING_USAGE,
717 segment.hir_id,
718 segment.ident.span,
719 SupertraitItemShadowing { shadower, shadowee, item: segment.ident.name, subtrait },
720 );
721 }
722
723 fn upcast(
724 &mut self,
725 source_trait_ref: ty::PolyTraitRef<'tcx>,
726 target_trait_def_id: DefId,
727 ) -> ty::PolyTraitRef<'tcx> {
728 let upcast_trait_refs =
729 traits::upcast_choices(self.tcx, source_trait_ref, target_trait_def_id);
730
731 if let &[upcast_trait_ref] = upcast_trait_refs.as_slice() {
733 upcast_trait_ref
734 } else {
735 self.dcx().span_delayed_bug(
736 self.span,
737 format!(
738 "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
739 source_trait_ref, target_trait_def_id, upcast_trait_refs
740 ),
741 );
742
743 ty::Binder::dummy(ty::TraitRef::new_from_args(
744 self.tcx,
745 target_trait_def_id,
746 ty::GenericArgs::extend_with_error(self.tcx, target_trait_def_id, &[]),
747 ))
748 }
749 }
750
751 fn instantiate_binder_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
752 where
753 T: TypeFoldable<TyCtxt<'tcx>> + Copy,
754 {
755 self.fcx.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, value)
756 }
757}