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