1use rustc_errors::ErrorGuaranteed;
2use rustc_hir::LangItem;
3use rustc_hir::def_id::DefId;
4use rustc_infer::infer::TyCtxtInferExt;
5use rustc_middle::bug;
6use rustc_middle::query::Providers;
7use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError};
8use rustc_middle::ty::{
9 self, ClosureKind, GenericArgsRef, Instance, PseudoCanonicalInput, TyCtxt, TypeVisitableExt,
10};
11use rustc_span::sym;
12use rustc_trait_selection::traits;
13use tracing::debug;
14use traits::translate_args;
15
16use crate::errors::UnexpectedFnPtrAssociatedItem;
17
18fn resolve_instance_raw<'tcx>(
19 tcx: TyCtxt<'tcx>,
20 key: ty::PseudoCanonicalInput<'tcx, (DefId, GenericArgsRef<'tcx>)>,
21) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
22 let PseudoCanonicalInput { typing_env, value: (def_id, args) } = key;
23
24 let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
25 debug!(" => associated item, attempting to find impl in typing_env {:#?}", typing_env);
26 resolve_associated_item(
27 tcx,
28 def_id,
29 typing_env,
30 trait_def_id,
31 tcx.normalize_erasing_regions(typing_env, args),
32 )
33 } else {
34 let def = if tcx.intrinsic(def_id).is_some() {
35 debug!(" => intrinsic");
36 ty::InstanceKind::Intrinsic(def_id)
37 } else if tcx.is_lang_item(def_id, LangItem::DropInPlace) {
38 let ty = args.type_at(0);
39
40 if ty.needs_drop(tcx, typing_env) {
41 debug!(" => nontrivial drop glue");
42 match *ty.kind() {
43 ty::Coroutine(coroutine_def_id, ..) => {
44 if tcx.optimized_mir(coroutine_def_id).coroutine_drop_async().is_some() {
47 ty::InstanceKind::DropGlue(def_id, None)
48 } else {
49 ty::InstanceKind::DropGlue(def_id, Some(ty))
50 }
51 }
52 ty::Closure(..)
53 | ty::CoroutineClosure(..)
54 | ty::Tuple(..)
55 | ty::Adt(..)
56 | ty::Dynamic(..)
57 | ty::Array(..)
58 | ty::Slice(..)
59 | ty::UnsafeBinder(..) => ty::InstanceKind::DropGlue(def_id, Some(ty)),
60 _ => return Ok(None),
62 }
63 } else {
64 debug!(" => trivial drop glue");
65 ty::InstanceKind::DropGlue(def_id, None)
66 }
67 } else if tcx.is_lang_item(def_id, LangItem::AsyncDropInPlace) {
68 let ty = args.type_at(0);
69
70 if ty.needs_async_drop(tcx, typing_env) {
71 match *ty.kind() {
72 ty::Closure(..)
73 | ty::CoroutineClosure(..)
74 | ty::Coroutine(..)
75 | ty::Tuple(..)
76 | ty::Adt(..)
77 | ty::Dynamic(..)
78 | ty::Array(..)
79 | ty::Slice(..) => {}
80 _ => return Ok(None),
82 }
83 debug!(" => nontrivial async drop glue ctor");
84 ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty)
85 } else {
86 debug!(" => trivial async drop glue ctor");
87 ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty)
88 }
89 } else if tcx.is_async_drop_in_place_coroutine(def_id) {
90 let ty = args.type_at(0);
91 ty::InstanceKind::AsyncDropGlue(def_id, ty)
92 } else {
93 debug!(" => free item");
94 ty::InstanceKind::Item(def_id)
95 };
96
97 Ok(Some(Instance { def, args }))
98 };
99 debug!("resolve_instance: result={:?}", result);
100 result
101}
102
103fn resolve_associated_item<'tcx>(
104 tcx: TyCtxt<'tcx>,
105 trait_item_id: DefId,
106 typing_env: ty::TypingEnv<'tcx>,
107 trait_id: DefId,
108 rcvr_args: GenericArgsRef<'tcx>,
109) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
110 debug!(?trait_item_id, ?typing_env, ?trait_id, ?rcvr_args, "resolve_associated_item");
111
112 let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args);
113
114 let input = typing_env.as_query_input(trait_ref);
115 let vtbl = match tcx.codegen_select_candidate(input) {
116 Ok(vtbl) => vtbl,
117 Err(CodegenObligationError::Ambiguity | CodegenObligationError::Unimplemented) => {
118 return Ok(None);
119 }
120 Err(CodegenObligationError::UnconstrainedParam(guar)) => return Err(guar),
121 };
122
123 Ok(match vtbl {
126 traits::ImplSource::UserDefined(impl_data) => {
127 debug!(
128 "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
129 typing_env, trait_item_id, rcvr_args, impl_data
130 );
131 assert!(!rcvr_args.has_infer());
132 assert!(!trait_ref.has_infer());
133
134 let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
135 let trait_def = tcx.trait_def(trait_def_id);
136 let leaf_def = trait_def
137 .ancestors(tcx, impl_data.impl_def_id)?
138 .leaf_def(tcx, trait_item_id)
139 .unwrap_or_else(|| {
140 bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
141 });
142
143 let eligible = if leaf_def.is_final() {
150 true
152 } else {
153 match typing_env.typing_mode {
158 ty::TypingMode::Coherence
159 | ty::TypingMode::Analysis { .. }
160 | ty::TypingMode::Borrowck { .. }
161 | ty::TypingMode::PostBorrowckAnalysis { .. } => false,
162 ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(),
163 }
164 };
165 if !eligible {
166 return Ok(None);
167 }
168
169 let typing_env = typing_env.with_post_analysis_normalized(tcx);
170 let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
171 let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args);
172 let args = translate_args(
173 &infcx,
174 param_env,
175 impl_data.impl_def_id,
176 args,
177 leaf_def.defining_node,
178 );
179 let args = infcx.tcx.erase_regions(args);
180
181 let self_ty = rcvr_args.type_at(0);
189 if !self_ty.is_known_rigid() {
190 let predicates = tcx
191 .predicates_of(impl_data.impl_def_id)
192 .instantiate(tcx, impl_data.args)
193 .predicates;
194 let sized_def_id = tcx.lang_items().sized_trait();
195 if !predicates.into_iter().filter_map(ty::Clause::as_trait_clause).any(|clause| {
198 Some(clause.def_id()) == sized_def_id
199 && clause.skip_binder().self_ty() == self_ty
200 }) {
201 return Ok(None);
202 }
203 }
204
205 if !leaf_def.item.defaultness(tcx).has_value() {
207 let guar = tcx.dcx().span_delayed_bug(
208 tcx.def_span(leaf_def.item.def_id),
209 "missing value for assoc item in impl",
210 );
211 return Err(guar);
212 }
213
214 if !tcx.check_args_compatible(leaf_def.item.def_id, args) {
218 let guar = tcx.dcx().span_delayed_bug(
219 tcx.def_span(leaf_def.item.def_id),
220 "missing value for assoc item in impl",
221 );
222 return Err(guar);
223 }
224
225 let args = tcx.erase_regions(args);
226
227 if trait_item_id != leaf_def.item.def_id
233 && let Some(leaf_def_item) = leaf_def.item.def_id.as_local()
234 {
235 tcx.ensure_ok().compare_impl_item(leaf_def_item)?;
236 }
237
238 Some(ty::Instance::new_raw(leaf_def.item.def_id, args))
239 }
240 traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => {
241 let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args);
242 if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() {
243 None
245 } else {
246 let vtable_base = tcx.first_method_vtable_slot(trait_ref);
247 let offset = tcx
248 .own_existential_vtable_entries(trait_id)
249 .iter()
250 .copied()
251 .position(|def_id| def_id == trait_item_id);
252 offset.map(|offset| Instance {
253 def: ty::InstanceKind::Virtual(trait_item_id, vtable_base + offset),
254 args: rcvr_args,
255 })
256 }
257 }
258 traits::ImplSource::Builtin(BuiltinImplSource::Misc | BuiltinImplSource::Trivial, _) => {
259 if tcx.is_lang_item(trait_ref.def_id, LangItem::Clone) {
260 let name = tcx.item_name(trait_item_id);
262 if name == sym::clone {
263 let self_ty = trait_ref.self_ty();
264 match self_ty.kind() {
265 ty::FnDef(..) | ty::FnPtr(..) => (),
266 ty::Coroutine(..)
267 | ty::CoroutineWitness(..)
268 | ty::Closure(..)
269 | ty::CoroutineClosure(..)
270 | ty::Tuple(..) => {}
271 _ => return Ok(None),
272 };
273
274 Some(Instance {
275 def: ty::InstanceKind::CloneShim(trait_item_id, self_ty),
276 args: rcvr_args,
277 })
278 } else {
279 assert_eq!(name, sym::clone_from);
280
281 let args = tcx.erase_regions(rcvr_args);
283 Some(ty::Instance::new_raw(trait_item_id, args))
284 }
285 } else if tcx.is_lang_item(trait_ref.def_id, LangItem::FnPtrTrait) {
286 if tcx.is_lang_item(trait_item_id, LangItem::FnPtrAddr) {
287 let self_ty = trait_ref.self_ty();
288 if !matches!(self_ty.kind(), ty::FnPtr(..)) {
289 return Ok(None);
290 }
291 Some(Instance {
292 def: ty::InstanceKind::FnPtrAddrShim(trait_item_id, self_ty),
293 args: rcvr_args,
294 })
295 } else {
296 tcx.dcx().emit_fatal(UnexpectedFnPtrAssociatedItem {
297 span: tcx.def_span(trait_item_id),
298 })
299 }
300 } else if let Some(target_kind) = tcx.fn_trait_kind_from_def_id(trait_ref.def_id) {
301 if cfg!(debug_assertions)
305 && ![sym::call, sym::call_mut, sym::call_once]
306 .contains(&tcx.item_name(trait_item_id))
307 {
308 bug!(
313 "no definition for `{trait_ref}::{}` for built-in callable type",
314 tcx.item_name(trait_item_id)
315 )
316 }
317 match *rcvr_args.type_at(0).kind() {
318 ty::Closure(closure_def_id, args) => {
319 Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind))
320 }
321 ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
322 def: ty::InstanceKind::FnPtrShim(trait_item_id, rcvr_args.type_at(0)),
323 args: rcvr_args,
324 }),
325 ty::CoroutineClosure(coroutine_closure_def_id, args) => {
326 if ty::ClosureKind::FnOnce == args.as_coroutine_closure().kind() {
332 Some(Instance::new_raw(coroutine_closure_def_id, args))
333 } else {
334 Some(Instance {
335 def: ty::InstanceKind::ConstructCoroutineInClosureShim {
336 coroutine_closure_def_id,
337 receiver_by_ref: target_kind != ty::ClosureKind::FnOnce,
338 },
339 args,
340 })
341 }
342 }
343 _ => bug!(
344 "no built-in definition for `{trait_ref}::{}` for non-fn type",
345 tcx.item_name(trait_item_id)
346 ),
347 }
348 } else if let Some(target_kind) = tcx.async_fn_trait_kind_from_def_id(trait_ref.def_id)
349 {
350 match *rcvr_args.type_at(0).kind() {
351 ty::CoroutineClosure(coroutine_closure_def_id, args) => {
352 if target_kind == ClosureKind::FnOnce
353 && args.as_coroutine_closure().kind() != ClosureKind::FnOnce
354 {
355 Some(Instance {
358 def: ty::InstanceKind::ConstructCoroutineInClosureShim {
359 coroutine_closure_def_id,
360 receiver_by_ref: false,
361 },
362 args,
363 })
364 } else {
365 Some(Instance::new_raw(coroutine_closure_def_id, args))
366 }
367 }
368 ty::Closure(closure_def_id, args) => {
369 Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind))
370 }
371 ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
372 def: ty::InstanceKind::FnPtrShim(trait_item_id, rcvr_args.type_at(0)),
373 args: rcvr_args,
374 }),
375 _ => bug!(
376 "no built-in definition for `{trait_ref}::{}` for non-lending-closure type",
377 tcx.item_name(trait_item_id)
378 ),
379 }
380 } else if tcx.is_lang_item(trait_ref.def_id, LangItem::TransmuteTrait) {
381 let name = tcx.item_name(trait_item_id);
382 assert_eq!(name, sym::transmute);
383 let args = tcx.erase_regions(rcvr_args);
384 Some(ty::Instance::new_raw(trait_item_id, args))
385 } else {
386 Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args)
387 }
388 }
389 traits::ImplSource::Param(..)
390 | traits::ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) => None,
391 })
392}
393
394pub(crate) fn provide(providers: &mut Providers) {
395 *providers = Providers { resolve_instance_raw, ..*providers };
396}