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
146 self.check_for_illegal_method_calls(pick);
148
149 self.lint_shadowed_supertrait_items(pick, segment);
151
152 if illegal_sized_bound.is_none() {
156 self.add_obligations(method_sig, all_args, method_predicates, pick.item.def_id);
157 }
158
159 let callee = MethodCallee { def_id: pick.item.def_id, args: all_args, sig: method_sig };
161 ConfirmResult { callee, illegal_sized_bound }
162 }
163
164 fn adjust_self_ty(
168 &mut self,
169 unadjusted_self_ty: Ty<'tcx>,
170 pick: &probe::Pick<'tcx>,
171 ) -> Ty<'tcx> {
172 let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty);
175 let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
176 return Ty::new_error_with_message(
177 self.tcx,
178 DUMMY_SP,
179 format!("failed autoderef {}", pick.autoderefs),
180 );
181 };
182 assert_eq!(n, pick.autoderefs);
183
184 let mut adjustments = self.adjust_steps(&autoderef);
185 let mut target = self.structurally_resolve_type(autoderef.span(), ty);
186
187 match pick.autoref_or_ptr_adjustment {
188 Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
189 let region = self.next_region_var(RegionVariableOrigin::Autoref(self.span));
190 let base_ty = target;
192
193 target = Ty::new_ref(self.tcx, region, target, mutbl);
194
195 let mutbl = AutoBorrowMutability::new(mutbl, AllowTwoPhase::Yes);
198
199 adjustments
200 .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target });
201
202 if unsize {
203 let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
204 Ty::new_slice(self.tcx, *elem_ty)
205 } else {
206 bug!(
207 "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
208 base_ty
209 )
210 };
211 target = Ty::new_ref(self.tcx, region, unsized_ty, mutbl.into());
212 adjustments.push(Adjustment {
213 kind: Adjust::Pointer(PointerCoercion::Unsize),
214 target,
215 });
216 }
217 }
218 Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
219 target = match target.kind() {
220 &ty::RawPtr(ty, mutbl) => {
221 assert!(mutbl.is_mut());
222 Ty::new_imm_ptr(self.tcx, ty)
223 }
224 other => panic!("Cannot adjust receiver type {other:?} to const ptr"),
225 };
226
227 adjustments.push(Adjustment {
228 kind: Adjust::Pointer(PointerCoercion::MutToConstPointer),
229 target,
230 });
231 }
232
233 Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
234 let region = self.next_region_var(RegionVariableOrigin::Autoref(self.span));
235
236 target = match target.kind() {
237 ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
238 let inner_ty = match args[0].expect_ty().kind() {
239 ty::Ref(_, ty, _) => *ty,
240 _ => bug!("Expected a reference type for argument to Pin"),
241 };
242 Ty::new_pinned_ref(self.tcx, region, inner_ty, mutbl)
243 }
244 _ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"),
245 };
246
247 adjustments.push(Adjustment { kind: Adjust::ReborrowPin(mutbl), target });
248 }
249 None => {}
250 }
251
252 self.register_predicates(autoderef.into_obligations());
253
254 if !self.skip_record_for_diagnostics {
256 self.apply_adjustments(self.self_expr, adjustments);
257 }
258
259 target
260 }
261
262 fn fresh_receiver_args(
269 &mut self,
270 self_ty: Ty<'tcx>,
271 pick: &probe::Pick<'tcx>,
272 ) -> GenericArgsRef<'tcx> {
273 match pick.kind {
274 probe::InherentImplPick => {
275 let impl_def_id = pick.item.container_id(self.tcx);
276 assert!(
277 self.tcx.impl_trait_ref(impl_def_id).is_none(),
278 "impl {impl_def_id:?} is not an inherent impl"
279 );
280 self.fresh_args_for_item(self.span, impl_def_id)
281 }
282
283 probe::ObjectPick => {
284 let trait_def_id = pick.item.container_id(self.tcx);
285
286 if !self.tcx.is_dyn_compatible(trait_def_id) {
291 return ty::GenericArgs::extend_with_error(self.tcx, trait_def_id, &[]);
292 }
293
294 if self_ty.references_error() {
301 return ty::GenericArgs::extend_with_error(self.tcx, trait_def_id, &[]);
302 }
303
304 self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
305 let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty);
316 let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
317 let upcast_trait_ref =
318 this.instantiate_binder_with_fresh_vars(upcast_poly_trait_ref);
319 debug!(
320 "original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
321 original_poly_trait_ref, upcast_trait_ref, trait_def_id
322 );
323 upcast_trait_ref.args
324 })
325 }
326
327 probe::TraitPick => {
328 let trait_def_id = pick.item.container_id(self.tcx);
329
330 self.fresh_args_for_item(self.span, trait_def_id)
336 }
337
338 probe::WhereClausePick(poly_trait_ref) => {
339 self.instantiate_binder_with_fresh_vars(poly_trait_ref).args
342 }
343 }
344 }
345
346 fn extract_existential_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R
347 where
348 F: FnMut(&mut ConfirmContext<'a, 'tcx>, Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>) -> R,
349 {
350 let mut autoderef = self.fcx.autoderef(self.span, self_ty);
356
357 if self.tcx.features().arbitrary_self_types()
360 || self.tcx.features().arbitrary_self_types_pointers()
361 {
362 autoderef = autoderef.use_receiver_trait();
363 }
364
365 autoderef
366 .include_raw_pointers()
367 .find_map(|(ty, _)| match ty.kind() {
368 ty::Dynamic(data, ..) => Some(closure(
369 self,
370 ty,
371 data.principal().unwrap_or_else(|| {
372 span_bug!(self.span, "calling trait method on empty object?")
373 }),
374 )),
375 _ => None,
376 })
377 .unwrap_or_else(|| {
378 span_bug!(
379 self.span,
380 "self-type `{}` for ObjectPick never dereferenced to an object",
381 self_ty
382 )
383 })
384 }
385
386 fn instantiate_method_args(
387 &mut self,
388 pick: &probe::Pick<'tcx>,
389 seg: &hir::PathSegment<'tcx>,
390 parent_args: GenericArgsRef<'tcx>,
391 ) -> GenericArgsRef<'tcx> {
392 let generics = self.tcx.generics_of(pick.item.def_id);
396
397 let arg_count_correct = check_generic_arg_count_for_call(
398 self.fcx,
399 pick.item.def_id,
400 generics,
401 seg,
402 IsMethodCall::Yes,
403 );
404
405 assert_eq!(generics.parent_count, parent_args.len());
408
409 struct GenericArgsCtxt<'a, 'tcx> {
410 cfcx: &'a ConfirmContext<'a, 'tcx>,
411 pick: &'a probe::Pick<'tcx>,
412 seg: &'a hir::PathSegment<'tcx>,
413 }
414 impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for GenericArgsCtxt<'a, 'tcx> {
415 fn args_for_def_id(
416 &mut self,
417 def_id: DefId,
418 ) -> (Option<&'a hir::GenericArgs<'tcx>>, bool) {
419 if def_id == self.pick.item.def_id {
420 if let Some(data) = self.seg.args {
421 return (Some(data), false);
422 }
423 }
424 (None, false)
425 }
426
427 fn provided_kind(
428 &mut self,
429 preceding_args: &[ty::GenericArg<'tcx>],
430 param: &ty::GenericParamDef,
431 arg: &GenericArg<'tcx>,
432 ) -> ty::GenericArg<'tcx> {
433 match (¶m.kind, arg) {
434 (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self
435 .cfcx
436 .fcx
437 .lowerer()
438 .lower_lifetime(lt, RegionInferReason::Param(param))
439 .into(),
440 (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
441 self.cfcx.lower_ty(ty.as_unambig_ty()).raw.into()
443 }
444 (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
445 self.cfcx.lower_ty(&inf.to_ty()).raw.into()
446 }
447 (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
448 .cfcx
449 .lower_const_arg(
451 ct.as_unambig_ct(),
452 FeedConstTy::Param(param.def_id, preceding_args),
453 )
454 .into(),
455 (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
456 self.cfcx.ct_infer(Some(param), inf.span).into()
457 }
458 (kind, arg) => {
459 bug!("mismatched method arg kind {kind:?} in turbofish: {arg:?}")
460 }
461 }
462 }
463
464 fn inferred_kind(
465 &mut self,
466 _preceding_args: &[ty::GenericArg<'tcx>],
467 param: &ty::GenericParamDef,
468 _infer_args: bool,
469 ) -> ty::GenericArg<'tcx> {
470 self.cfcx.var_for_def(self.cfcx.span, param)
471 }
472 }
473
474 let args = lower_generic_args(
475 self.fcx,
476 pick.item.def_id,
477 parent_args,
478 false,
479 None,
480 &arg_count_correct,
481 &mut GenericArgsCtxt { cfcx: self, pick, seg },
482 );
483
484 if !args.is_empty() && !generics.is_own_empty() {
499 let user_type_annotation = self.probe(|_| {
500 let user_args = UserArgs {
501 args: GenericArgs::for_item(self.tcx, pick.item.def_id, |param, _| {
502 let i = param.index as usize;
503 if i < generics.parent_count {
504 self.fcx.var_for_def(DUMMY_SP, param)
505 } else {
506 args[i]
507 }
508 }),
509 user_self_ty: None, };
511
512 self.fcx.canonicalize_user_type_annotation(ty::UserType::new(
513 ty::UserTypeKind::TypeOf(pick.item.def_id, user_args),
514 ))
515 });
516
517 debug!("instantiate_method_args: user_type_annotation={:?}", user_type_annotation);
518
519 if !self.skip_record_for_diagnostics {
520 self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation);
521 }
522 }
523
524 self.normalize(self.span, args)
525 }
526
527 fn unify_receivers(
528 &mut self,
529 self_ty: Ty<'tcx>,
530 method_self_ty: Ty<'tcx>,
531 pick: &probe::Pick<'tcx>,
532 ) {
533 debug!(
534 "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}",
535 self_ty, method_self_ty, self.span, pick
536 );
537 let cause = self.cause(self.self_expr.span, ObligationCauseCode::Misc);
538 match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::Yes, method_self_ty, self_ty) {
539 Ok(InferOk { obligations, value: () }) => {
540 self.register_predicates(obligations);
541 }
542 Err(terr) => {
543 if self.tcx.features().arbitrary_self_types() {
544 self.err_ctxt()
545 .report_mismatched_types(
546 &cause,
547 self.param_env,
548 method_self_ty,
549 self_ty,
550 terr,
551 )
552 .emit();
553 } else {
554 self.dcx().span_delayed_bug(
557 cause.span,
558 format!("{self_ty} was a subtype of {method_self_ty} but now is not?"),
559 );
560 }
561 }
562 }
563 }
564
565 fn instantiate_method_sig(
569 &mut self,
570 pick: &probe::Pick<'tcx>,
571 all_args: GenericArgsRef<'tcx>,
572 ) -> (ty::FnSig<'tcx>, ty::InstantiatedPredicates<'tcx>) {
573 debug!("instantiate_method_sig(pick={:?}, all_args={:?})", pick, all_args);
574
575 let def_id = pick.item.def_id;
579 let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args);
580
581 debug!("method_predicates after instantiation = {:?}", method_predicates);
582
583 let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, all_args);
584 debug!("type scheme instantiated, sig={:?}", sig);
585
586 let sig = self.instantiate_binder_with_fresh_vars(sig);
587 debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
588
589 (sig, method_predicates)
590 }
591
592 fn add_obligations(
593 &mut self,
594 sig: ty::FnSig<'tcx>,
595 all_args: GenericArgsRef<'tcx>,
596 method_predicates: ty::InstantiatedPredicates<'tcx>,
597 def_id: DefId,
598 ) {
599 debug!(
600 "add_obligations: sig={:?} all_args={:?} method_predicates={:?} def_id={:?}",
601 sig, all_args, method_predicates, def_id
602 );
603
604 for obligation in traits::predicates_for_generics(
608 |idx, span| {
609 let code = ObligationCauseCode::WhereClauseInExpr(
610 def_id,
611 span,
612 self.call_expr.hir_id,
613 idx,
614 );
615 self.cause(self.span, code)
616 },
617 self.param_env,
618 method_predicates,
619 ) {
620 self.register_predicate(obligation);
621 }
622
623 self.add_wf_bounds(all_args, self.call_expr.span);
626
627 for ty in sig.inputs_and_output {
631 self.register_wf_obligation(
632 ty.into(),
633 self.span,
634 ObligationCauseCode::WellFormed(None),
635 );
636 }
637 }
638
639 fn predicates_require_illegal_sized_bound(
643 &self,
644 predicates: ty::InstantiatedPredicates<'tcx>,
645 ) -> Option<Span> {
646 let sized_def_id = self.tcx.lang_items().sized_trait()?;
647
648 traits::elaborate(self.tcx, predicates.predicates.iter().copied())
649 .filter_map(|pred| match pred.kind().skip_binder() {
651 ty::ClauseKind::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
652 let span = predicates
653 .iter()
654 .find_map(|(p, span)| if p == pred { Some(span) } else { None })
655 .unwrap_or(DUMMY_SP);
656 Some((trait_pred, span))
657 }
658 _ => None,
659 })
660 .find_map(|(trait_pred, span)| match trait_pred.self_ty().kind() {
661 ty::Dynamic(..) => Some(span),
662 _ => None,
663 })
664 }
665
666 fn check_for_illegal_method_calls(&self, pick: &probe::Pick<'_>) {
667 if let Some(trait_def_id) = pick.item.trait_container(self.tcx)
669 && let Err(e) = callee::check_legal_trait_for_method_call(
670 self.tcx,
671 self.span,
672 Some(self.self_expr.span),
673 self.call_expr.span,
674 trait_def_id,
675 self.body_id.to_def_id(),
676 )
677 {
678 self.set_tainted_by_errors(e);
679 }
680 }
681
682 fn lint_shadowed_supertrait_items(
683 &self,
684 pick: &probe::Pick<'_>,
685 segment: &hir::PathSegment<'tcx>,
686 ) {
687 if pick.shadowed_candidates.is_empty() {
688 return;
689 }
690
691 let shadower_span = self.tcx.def_span(pick.item.def_id);
692 let subtrait = self.tcx.item_name(pick.item.trait_container(self.tcx).unwrap());
693 let shadower = SupertraitItemShadower { span: shadower_span, subtrait };
694
695 let shadowee = if let [shadowee] = &pick.shadowed_candidates[..] {
696 let shadowee_span = self.tcx.def_span(shadowee.def_id);
697 let supertrait = self.tcx.item_name(shadowee.trait_container(self.tcx).unwrap());
698 SupertraitItemShadowee::Labeled { span: shadowee_span, supertrait }
699 } else {
700 let (traits, spans): (Vec<_>, Vec<_>) = pick
701 .shadowed_candidates
702 .iter()
703 .map(|item| {
704 (
705 self.tcx.item_name(item.trait_container(self.tcx).unwrap()),
706 self.tcx.def_span(item.def_id),
707 )
708 })
709 .unzip();
710 SupertraitItemShadowee::Several { traits: traits.into(), spans: spans.into() }
711 };
712
713 self.tcx.emit_node_span_lint(
714 SUPERTRAIT_ITEM_SHADOWING_USAGE,
715 segment.hir_id,
716 segment.ident.span,
717 SupertraitItemShadowing { shadower, shadowee, item: segment.ident.name, subtrait },
718 );
719 }
720
721 fn upcast(
722 &mut self,
723 source_trait_ref: ty::PolyTraitRef<'tcx>,
724 target_trait_def_id: DefId,
725 ) -> ty::PolyTraitRef<'tcx> {
726 let upcast_trait_refs =
727 traits::upcast_choices(self.tcx, source_trait_ref, target_trait_def_id);
728
729 if let &[upcast_trait_ref] = upcast_trait_refs.as_slice() {
731 upcast_trait_ref
732 } else {
733 self.dcx().span_delayed_bug(
734 self.span,
735 format!(
736 "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
737 source_trait_ref, target_trait_def_id, upcast_trait_refs
738 ),
739 );
740
741 ty::Binder::dummy(ty::TraitRef::new_from_args(
742 self.tcx,
743 target_trait_def_id,
744 ty::GenericArgs::extend_with_error(self.tcx, target_trait_def_id, &[]),
745 ))
746 }
747 }
748
749 fn instantiate_binder_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
750 where
751 T: TypeFoldable<TyCtxt<'tcx>> + Copy,
752 {
753 self.fcx.instantiate_binder_with_fresh_vars(
754 self.span,
755 BoundRegionConversionTime::FnCall,
756 value,
757 )
758 }
759}