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_assoc(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_assoc(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.impl_trait_id(impl_data.impl_def_id);
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_and_anonymize_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 if trait_item_id != leaf_def.item.def_id
231 && let Some(leaf_def_item) = leaf_def.item.def_id.as_local()
232 {
233 tcx.ensure_ok().compare_impl_item(leaf_def_item)?;
234 }
235
236 Some(ty::Instance::new_raw(leaf_def.item.def_id, args))
237 }
238 traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => {
239 let trait_ref = ty::TraitRef::from_assoc(tcx, trait_id, rcvr_args);
240 if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() {
241 None
243 } else {
244 let vtable_base = tcx.first_method_vtable_slot(trait_ref);
245 let offset = tcx
246 .own_existential_vtable_entries(trait_id)
247 .iter()
248 .copied()
249 .position(|def_id| def_id == trait_item_id);
250 offset.map(|offset| Instance {
251 def: ty::InstanceKind::Virtual(trait_item_id, vtable_base + offset),
252 args: rcvr_args,
253 })
254 }
255 }
256 traits::ImplSource::Builtin(BuiltinImplSource::Misc | BuiltinImplSource::Trivial, _) => {
257 if tcx.is_lang_item(trait_ref.def_id, LangItem::Clone) {
258 let name = tcx.item_name(trait_item_id);
260 if name == sym::clone {
261 let self_ty = trait_ref.self_ty();
262 match self_ty.kind() {
263 ty::FnDef(..) | ty::FnPtr(..) => (),
264 ty::Coroutine(..)
265 | ty::CoroutineWitness(..)
266 | ty::Closure(..)
267 | ty::CoroutineClosure(..)
268 | ty::Tuple(..) => {}
269 _ => return Ok(None),
270 };
271
272 Some(Instance {
273 def: ty::InstanceKind::CloneShim(trait_item_id, self_ty),
274 args: rcvr_args,
275 })
276 } else {
277 assert_eq!(name, sym::clone_from);
278
279 let args = tcx.erase_and_anonymize_regions(rcvr_args);
281 Some(ty::Instance::new_raw(trait_item_id, args))
282 }
283 } else if tcx.is_lang_item(trait_ref.def_id, LangItem::FnPtrTrait) {
284 if tcx.is_lang_item(trait_item_id, LangItem::FnPtrAddr) {
285 let self_ty = trait_ref.self_ty();
286 if !matches!(self_ty.kind(), ty::FnPtr(..)) {
287 return Ok(None);
288 }
289 Some(Instance {
290 def: ty::InstanceKind::FnPtrAddrShim(trait_item_id, self_ty),
291 args: rcvr_args,
292 })
293 } else {
294 tcx.dcx().emit_fatal(UnexpectedFnPtrAssociatedItem {
295 span: tcx.def_span(trait_item_id),
296 })
297 }
298 } else if let Some(target_kind) = tcx.fn_trait_kind_from_def_id(trait_ref.def_id) {
299 if cfg!(debug_assertions)
303 && ![sym::call, sym::call_mut, sym::call_once]
304 .contains(&tcx.item_name(trait_item_id))
305 {
306 bug!(
311 "no definition for `{trait_ref}::{}` for built-in callable type",
312 tcx.item_name(trait_item_id)
313 )
314 }
315 match *rcvr_args.type_at(0).kind() {
316 ty::Closure(closure_def_id, args) => {
317 Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind))
318 }
319 ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
320 def: ty::InstanceKind::FnPtrShim(trait_item_id, rcvr_args.type_at(0)),
321 args: rcvr_args,
322 }),
323 ty::CoroutineClosure(coroutine_closure_def_id, args) => {
324 if ty::ClosureKind::FnOnce == args.as_coroutine_closure().kind() {
330 Some(Instance::new_raw(coroutine_closure_def_id, args))
331 } else {
332 Some(Instance {
333 def: ty::InstanceKind::ConstructCoroutineInClosureShim {
334 coroutine_closure_def_id,
335 receiver_by_ref: target_kind != ty::ClosureKind::FnOnce,
336 },
337 args,
338 })
339 }
340 }
341 _ => bug!(
342 "no built-in definition for `{trait_ref}::{}` for non-fn type",
343 tcx.item_name(trait_item_id)
344 ),
345 }
346 } else if let Some(target_kind) = tcx.async_fn_trait_kind_from_def_id(trait_ref.def_id)
347 {
348 match *rcvr_args.type_at(0).kind() {
349 ty::CoroutineClosure(coroutine_closure_def_id, args) => {
350 if target_kind == ClosureKind::FnOnce
351 && args.as_coroutine_closure().kind() != ClosureKind::FnOnce
352 {
353 Some(Instance {
356 def: ty::InstanceKind::ConstructCoroutineInClosureShim {
357 coroutine_closure_def_id,
358 receiver_by_ref: false,
359 },
360 args,
361 })
362 } else {
363 Some(Instance::new_raw(coroutine_closure_def_id, args))
364 }
365 }
366 ty::Closure(closure_def_id, args) => {
367 Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind))
368 }
369 ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
370 def: ty::InstanceKind::FnPtrShim(trait_item_id, rcvr_args.type_at(0)),
371 args: rcvr_args,
372 }),
373 _ => bug!(
374 "no built-in definition for `{trait_ref}::{}` for non-lending-closure type",
375 tcx.item_name(trait_item_id)
376 ),
377 }
378 } else if tcx.is_lang_item(trait_ref.def_id, LangItem::TransmuteTrait) {
379 let name = tcx.item_name(trait_item_id);
380 assert_eq!(name, sym::transmute);
381 let args = tcx.erase_and_anonymize_regions(rcvr_args);
382 Some(ty::Instance::new_raw(trait_item_id, args))
383 } else {
384 Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args)
385 }
386 }
387 traits::ImplSource::Param(..)
388 | traits::ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) => None,
389 })
390}
391
392pub(crate) fn provide(providers: &mut Providers) {
393 *providers = Providers { resolve_instance_raw, ..*providers };
394}