1use hir_def::{
5 FunctionId, GenericDefId, GenericParamId, TraitId,
6 expr_store::path::{GenericArg as HirGenericArg, GenericArgs as HirGenericArgs},
7 hir::{ExprId, generics::GenericParamDataRef},
8 type_ref::TypeRefId,
9};
10use rustc_type_ir::{
11 TypeFoldable,
12 elaborate::elaborate,
13 inherent::{BoundExistentialPredicates, IntoKind, Ty as _},
14};
15use tracing::debug;
16
17use crate::{
18 Adjust, Adjustment, AutoBorrow, IncorrectGenericsLenKind, InferenceDiagnostic,
19 LifetimeElisionKind, PointerCast, Span,
20 db::HirDatabase,
21 infer::{AllowTwoPhase, AutoBorrowMutability, ExplicitDropMethodUseKind, InferenceContext},
22 lower::{
23 GenericPredicates,
24 path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings},
25 },
26 method_resolution::{CandidateId, MethodCallee, probe},
27 next_solver::{
28 Binder, Clause, ClauseKind, Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, FnSig,
29 GenericArg, GenericArgs, ParamConst, PolyExistentialTraitRef, PolyTraitRef, Region,
30 TraitRef, Ty, TyKind, Unnormalized,
31 infer::{
32 BoundRegionConversionTime, InferCtxt,
33 traits::{ObligationCause, PredicateObligation},
34 },
35 util::{clauses_as_obligations, upcast_choices},
36 },
37};
38
39struct ConfirmContext<'a, 'db> {
40 ctx: &'a mut InferenceContext<'db>,
41 candidate: FunctionId,
42 call_expr: ExprId,
43}
44
45#[derive(Debug)]
46pub(crate) struct ConfirmResult<'db> {
47 pub(crate) callee: MethodCallee<'db>,
48 pub(crate) illegal_sized_bound: bool,
49 pub(crate) adjustments: Box<[Adjustment]>,
50}
51
52impl<'db> InferenceContext<'db> {
53 pub(crate) fn confirm_method(
54 &mut self,
55 pick: &probe::Pick<'db>,
56 unadjusted_self_ty: Ty<'db>,
57 expr: ExprId,
58 generic_args: Option<&HirGenericArgs>,
59 ) -> ConfirmResult<'db> {
60 debug!(
61 "confirm(unadjusted_self_ty={:?}, pick={:?}, generic_args={:?})",
62 unadjusted_self_ty, pick, generic_args,
63 );
64
65 let CandidateId::FunctionId(candidate) = pick.item else {
66 panic!("confirmation is only done for method calls, not path lookups");
67 };
68 let mut confirm_cx = ConfirmContext::new(self, candidate, expr);
69 confirm_cx.confirm(unadjusted_self_ty, pick, generic_args)
70 }
71}
72
73impl<'a, 'db> ConfirmContext<'a, 'db> {
74 fn new(
75 ctx: &'a mut InferenceContext<'db>,
76 candidate: FunctionId,
77 call_expr: ExprId,
78 ) -> ConfirmContext<'a, 'db> {
79 ConfirmContext { ctx, candidate, call_expr }
80 }
81
82 #[inline]
83 fn db(&self) -> &'db dyn HirDatabase {
84 self.ctx.table.infer_ctxt.interner.db
85 }
86
87 #[inline]
88 fn interner(&self) -> DbInterner<'db> {
89 self.ctx.table.infer_ctxt.interner
90 }
91
92 #[inline]
93 fn infcx(&self) -> &InferCtxt<'db> {
94 &self.ctx.table.infer_ctxt
95 }
96
97 fn confirm(
98 &mut self,
99 unadjusted_self_ty: Ty<'db>,
100 pick: &probe::Pick<'db>,
101 generic_args: Option<&HirGenericArgs>,
102 ) -> ConfirmResult<'db> {
103 let (self_ty, adjustments) = self.adjust_self_ty(unadjusted_self_ty, pick);
105
106 let rcvr_args = self.fresh_receiver_args(self_ty, pick);
108 let all_args = self.instantiate_method_args(generic_args, rcvr_args);
109
110 debug!("rcvr_args={rcvr_args:?}, all_args={all_args:?}");
111
112 let (method_sig, method_predicates) =
114 self.instantiate_method_sig(pick, all_args.as_slice());
115
116 let filler_args = GenericArgs::fill_rest(
125 self.interner(),
126 self.candidate.into(),
127 rcvr_args,
128 |index, id, _| match id {
129 GenericParamId::TypeParamId(id) => Ty::new_param(self.interner(), id, index).into(),
130 GenericParamId::ConstParamId(id) => {
131 Const::new_param(self.interner(), ParamConst { id, index }).into()
132 }
133 GenericParamId::LifetimeParamId(id) => {
134 Region::new_early_param(self.interner(), EarlyParamRegion { id, index }).into()
135 }
136 },
137 );
138 let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
139 GenericPredicates::query_all(self.db(), self.candidate.into())
140 .iter_instantiated(self.interner(), filler_args.as_slice())
141 .map(Unnormalized::skip_norm_wip),
142 );
143
144 let method_sig_rcvr = method_sig.inputs()[0];
151 debug!(
152 "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?}",
153 self_ty, method_sig_rcvr, method_sig
154 );
155 self.unify_receivers(self_ty, method_sig_rcvr, pick);
156
157 self.check_for_illegal_method_calls();
159
160 self.lint_shadowed_supertrait_items(pick);
162
163 if !illegal_sized_bound {
167 self.add_obligations(method_sig, all_args, method_predicates);
168 }
169
170 let callee = MethodCallee { def_id: self.candidate, args: all_args, sig: method_sig };
172 ConfirmResult { callee, illegal_sized_bound, adjustments }
173 }
174
175 fn adjust_self_ty(
179 &mut self,
180 unadjusted_self_ty: Ty<'db>,
181 pick: &probe::Pick<'db>,
182 ) -> (Ty<'db>, Box<[Adjustment]>) {
183 let mut autoderef =
186 self.ctx.table.autoderef_with_tracking(unadjusted_self_ty, self.call_expr.into());
187 let Some((mut target, n)) = autoderef.nth(pick.autoderefs) else {
188 return (Ty::new_error(self.interner(), ErrorGuaranteed), Box::new([]));
189 };
190 assert_eq!(n, pick.autoderefs);
191
192 let mut adjustments =
193 self.ctx.table.register_infer_ok(autoderef.adjust_steps_as_infer_ok());
194 match pick.autoref_or_ptr_adjustment {
195 Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
196 let region = self.infcx().next_region_var(self.call_expr.into());
197 let base_ty = target;
199
200 target = Ty::new_ref(self.interner(), region, target, mutbl);
201
202 let mutbl = AutoBorrowMutability::new(mutbl, AllowTwoPhase::Yes);
205
206 adjustments.push(Adjustment {
207 kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
208 target: target.store(),
209 });
210
211 if unsize {
212 let unsized_ty = if let TyKind::Array(elem_ty, _) = base_ty.kind() {
213 Ty::new_slice(self.interner(), elem_ty)
214 } else {
215 panic!(
216 "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {:?}",
217 base_ty
218 )
219 };
220 target = Ty::new_ref(self.interner(), region, unsized_ty, mutbl.into());
221 adjustments.push(Adjustment {
222 kind: Adjust::Pointer(PointerCast::Unsize),
223 target: target.store(),
224 });
225 }
226 }
227 Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
228 target = match target.kind() {
229 TyKind::RawPtr(ty, mutbl) => {
230 assert!(mutbl.is_mut());
231 Ty::new_imm_ptr(self.interner(), ty)
232 }
233 other => panic!("Cannot adjust receiver type {other:?} to const ptr"),
234 };
235
236 adjustments.push(Adjustment {
237 kind: Adjust::Pointer(PointerCast::MutToConstPointer),
238 target: target.store(),
239 });
240 }
241 None => {}
242 }
243
244 (target, adjustments.into_boxed_slice())
245 }
246
247 fn fresh_receiver_args(
254 &mut self,
255 self_ty: Ty<'db>,
256 pick: &probe::Pick<'db>,
257 ) -> GenericArgs<'db> {
258 match pick.kind {
259 probe::InherentImplPick(impl_def_id) => {
260 self.infcx().fresh_args_for_item(self.call_expr.into(), impl_def_id.into())
261 }
262
263 probe::ObjectPick(trait_def_id) => {
264 if self.db().dyn_compatibility_of_trait(trait_def_id).is_some() {
269 return GenericArgs::error_for_item(self.interner(), trait_def_id.into());
270 }
271
272 self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
273 let original_poly_trait_ref =
284 principal.with_self_ty(this.interner(), object_ty);
285 let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
286 let upcast_trait_ref =
287 this.instantiate_binder_with_fresh_vars(upcast_poly_trait_ref);
288 debug!(
289 "original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
290 original_poly_trait_ref, upcast_trait_ref, trait_def_id
291 );
292 upcast_trait_ref.args
293 })
294 }
295
296 probe::TraitPick(trait_def_id) => {
297 self.infcx().fresh_args_for_item(self.call_expr.into(), trait_def_id.into())
303 }
304
305 probe::WhereClausePick(poly_trait_ref) => {
306 self.instantiate_binder_with_fresh_vars(poly_trait_ref).args
309 }
310 }
311 }
312
313 fn extract_existential_trait_ref<R, F>(&self, self_ty: Ty<'db>, mut closure: F) -> R
314 where
315 F: FnMut(&ConfirmContext<'a, 'db>, Ty<'db>, PolyExistentialTraitRef<'db>) -> R,
316 {
317 let mut autoderef = self.ctx.table.autoderef(self_ty, self.call_expr.into());
323
324 if self.ctx.features.arbitrary_self_types || self.ctx.features.arbitrary_self_types_pointers
327 {
328 autoderef = autoderef.use_receiver_trait();
329 }
330
331 autoderef
332 .include_raw_pointers()
333 .find_map(|(ty, _)| match ty.kind() {
334 TyKind::Dynamic(data, ..) => Some(closure(
335 self,
336 ty,
337 data.principal().expect("calling trait method on empty object?"),
338 )),
339 _ => None,
340 })
341 .unwrap_or_else(|| {
342 panic!("self-type `{:?}` for ObjectPick never dereferenced to an object", self_ty)
343 })
344 }
345
346 fn instantiate_method_args(
347 &mut self,
348 generic_args: Option<&HirGenericArgs>,
349 parent_args: GenericArgs<'db>,
350 ) -> GenericArgs<'db> {
351 struct LowererCtx<'a, 'db> {
352 ctx: &'a mut InferenceContext<'db>,
353 expr: ExprId,
354 parent_args: &'a [GenericArg<'db>],
355 }
356
357 impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, 'db> {
358 fn report_len_mismatch(
359 &mut self,
360 def: GenericDefId,
361 provided_count: u32,
362 expected_count: u32,
363 kind: IncorrectGenericsLenKind,
364 ) {
365 self.ctx.push_diagnostic(InferenceDiagnostic::MethodCallIncorrectGenericsLen {
366 expr: self.expr,
367 provided_count,
368 expected_count,
369 kind,
370 def,
371 });
372 }
373
374 fn report_arg_mismatch(
375 &mut self,
376 param_id: GenericParamId,
377 arg_idx: u32,
378 has_self_arg: bool,
379 ) {
380 self.ctx.push_diagnostic(InferenceDiagnostic::MethodCallIncorrectGenericsOrder {
381 expr: self.expr,
382 param_id,
383 arg_idx,
384 has_self_arg,
385 });
386 }
387
388 fn provided_kind(
389 &mut self,
390 param_id: GenericParamId,
391 param: GenericParamDataRef<'_>,
392 arg: &HirGenericArg,
393 ) -> GenericArg<'db> {
394 match (param, arg) {
395 (
396 GenericParamDataRef::LifetimeParamData(_),
397 HirGenericArg::Lifetime(lifetime),
398 ) => self.ctx.make_body_lifetime(*lifetime).into(),
399 (GenericParamDataRef::TypeParamData(_), HirGenericArg::Type(type_ref)) => {
400 self.ctx.make_body_ty(*type_ref).into()
401 }
402 (GenericParamDataRef::ConstParamData(_), HirGenericArg::Const(konst)) => {
403 let GenericParamId::ConstParamId(const_id) = param_id else {
404 unreachable!("non-const param ID for const param");
405 };
406 let const_ty = self.ctx.db.const_param_ty(const_id);
407 self.ctx.create_body_anon_const(konst.expr, const_ty, false).into()
408 }
409 _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
410 }
411 }
412
413 fn provided_type_like_const(
414 &mut self,
415 _type_ref: TypeRefId,
416 _const_ty: Ty<'db>,
417 arg: TypeLikeConst<'_>,
418 ) -> Const<'db> {
419 match arg {
420 TypeLikeConst::Path(path) => self.ctx.make_path_as_body_const(path),
421 TypeLikeConst::Infer => self.ctx.table.next_const_var(Span::Dummy),
422 }
423 }
424
425 fn inferred_kind(
426 &mut self,
427 _def: GenericDefId,
428 param_id: GenericParamId,
429 _param: GenericParamDataRef<'_>,
430 infer_args: bool,
431 _preceding_args: &[GenericArg<'db>],
432 had_count_error: bool,
433 ) -> GenericArg<'db> {
434 let span =
437 if !infer_args || had_count_error { Span::Dummy } else { self.expr.into() };
438 self.ctx.table.var_for_def(param_id, span)
439 }
440
441 fn parent_arg(&mut self, param_idx: u32, _param_id: GenericParamId) -> GenericArg<'db> {
442 self.parent_args[param_idx as usize]
443 }
444
445 fn report_elided_lifetimes_in_path(
446 &mut self,
447 _def: GenericDefId,
448 _expected_count: u32,
449 _hard_error: bool,
450 ) {
451 unreachable!("we set `LifetimeElisionKind::Infer`")
452 }
453
454 fn report_elision_failure(&mut self, _def: GenericDefId, _expected_count: u32) {
455 unreachable!("we set `LifetimeElisionKind::Infer`")
456 }
457
458 fn report_missing_lifetime(&mut self, _def: GenericDefId, _expected_count: u32) {
459 unreachable!("we set `LifetimeElisionKind::Infer`")
460 }
461 }
462
463 substs_from_args_and_bindings(
464 self.db(),
465 self.ctx.store,
466 generic_args,
467 self.candidate.into(),
468 true,
469 LifetimeElisionKind::Infer,
470 false,
471 None,
472 &mut LowererCtx {
473 ctx: self.ctx,
474 expr: self.call_expr,
475 parent_args: parent_args.as_slice(),
476 },
477 )
478 }
479
480 fn unify_receivers(
481 &mut self,
482 self_ty: Ty<'db>,
483 method_self_ty: Ty<'db>,
484 pick: &probe::Pick<'db>,
485 ) {
486 debug!(
487 "unify_receivers: self_ty={:?} method_self_ty={:?} pick={:?}",
488 self_ty, method_self_ty, pick
489 );
490 let cause = ObligationCause::new(self.call_expr);
491 match self.ctx.table.at(&cause).sup(method_self_ty, self_ty) {
492 Ok(infer_ok) => {
493 self.ctx.table.register_infer_ok(infer_ok);
494 }
495 Err(_) => {
496 if self.ctx.features.arbitrary_self_types {
497 self.ctx.emit_type_mismatch(self.call_expr.into(), method_self_ty, self_ty);
498 }
499 }
500 }
501 }
502
503 fn instantiate_method_sig<'c>(
507 &mut self,
508 pick: &probe::Pick<'db>,
509 all_args: &'c [GenericArg<'db>],
510 ) -> (FnSig<'db>, impl Iterator<Item = PredicateObligation<'db>> + use<'c, 'db>) {
511 debug!("instantiate_method_sig(pick={:?}, all_args={:?})", pick, all_args);
512
513 let def_id = self.candidate;
517 let method_predicates = clauses_as_obligations(
518 GenericPredicates::query_all(self.db(), def_id.into())
519 .iter_instantiated(self.interner(), all_args)
520 .map(Unnormalized::skip_norm_wip),
521 ObligationCause::new(self.call_expr),
522 self.ctx.table.param_env,
523 );
524
525 let sig = self
526 .db()
527 .callable_item_signature(def_id.into())
528 .instantiate(self.interner(), all_args)
529 .skip_norm_wip();
530 debug!("type scheme instantiated, sig={:?}", sig);
531
532 let sig = self.instantiate_binder_with_fresh_vars(sig);
533 debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
534
535 (sig, method_predicates)
536 }
537
538 fn add_obligations(
539 &mut self,
540 sig: FnSig<'db>,
541 all_args: GenericArgs<'db>,
542 method_predicates: impl Iterator<Item = PredicateObligation<'db>>,
543 ) {
544 debug!("add_obligations: sig={:?} all_args={:?}", sig, all_args);
545
546 self.ctx.table.register_predicates(method_predicates);
547
548 self.ctx.table.add_wf_bounds(self.call_expr.into(), all_args);
551
552 for ty in sig.inputs_and_output {
556 self.ctx.table.register_wf_obligation(ty.into(), ObligationCause::new(self.call_expr));
557 }
558 }
559
560 fn predicates_require_illegal_sized_bound(
564 &self,
565 predicates: impl Iterator<Item = Clause<'db>>,
566 ) -> bool {
567 let Some(sized_def_id) = self.ctx.lang_items.Sized else {
568 return false;
569 };
570
571 elaborate(self.interner(), predicates)
572 .filter_map(|pred| match pred.kind().skip_binder() {
574 ClauseKind::Trait(trait_pred) if trait_pred.def_id().0 == sized_def_id => {
575 Some(trait_pred)
576 }
577 _ => None,
578 })
579 .any(|trait_pred| matches!(trait_pred.self_ty().kind(), TyKind::Dynamic(..)))
580 }
581
582 fn check_for_illegal_method_calls(&self) {
583 if self.ctx.lang_items.Drop_drop.is_some_and(|drop_fn| drop_fn == self.candidate) {
585 self.ctx.push_diagnostic(InferenceDiagnostic::ExplicitDropMethodUse {
586 kind: ExplicitDropMethodUseKind::MethodCall(self.call_expr),
587 });
588 }
589 }
590
591 #[expect(clippy::needless_return)]
592 fn lint_shadowed_supertrait_items(&self, pick: &probe::Pick<'_>) {
593 if pick.shadowed_candidates.is_empty() {
594 return;
595 }
596
597 }
599
600 fn upcast(
601 &self,
602 source_trait_ref: PolyTraitRef<'db>,
603 target_trait_def_id: TraitId,
604 ) -> PolyTraitRef<'db> {
605 let upcast_trait_refs =
606 upcast_choices(self.interner(), source_trait_ref, target_trait_def_id);
607
608 if let &[upcast_trait_ref] = upcast_trait_refs.as_slice() {
610 upcast_trait_ref
611 } else {
612 Binder::dummy(TraitRef::new_from_args(
613 self.interner(),
614 target_trait_def_id.into(),
615 GenericArgs::error_for_item(self.interner(), target_trait_def_id.into()),
616 ))
617 }
618 }
619
620 fn instantiate_binder_with_fresh_vars<T>(&self, value: Binder<'db, T>) -> T
621 where
622 T: TypeFoldable<DbInterner<'db>> + Copy,
623 {
624 self.infcx().instantiate_binder_with_fresh_vars(
625 self.call_expr.into(),
626 BoundRegionConversionTime::FnCall,
627 value,
628 )
629 }
630}