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