]>
Commit | Line | Data |
---|---|---|
5e7ed085 | 1 | use rustc_errors::ErrorGuaranteed; |
3dfed10e | 2 | use rustc_hir::def_id::{DefId, LocalDefId}; |
ba9703b0 | 3 | use rustc_infer::infer::TyCtxtInferExt; |
04454e1e | 4 | use rustc_middle::traits::CodegenObligationError; |
ba9703b0 | 5 | use rustc_middle::ty::subst::SubstsRef; |
9ffffee4 | 6 | use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt}; |
2b03887a | 7 | use rustc_span::sym; |
ba9703b0 XL |
8 | use rustc_trait_selection::traits; |
9 | use traits::{translate_substs, Reveal}; | |
74b04a01 | 10 | |
353b0b11 FG |
11 | use crate::errors::UnexpectedFnPtrAssociatedItem; |
12 | ||
f9f354fc | 13 | fn resolve_instance<'tcx>( |
74b04a01 | 14 | tcx: TyCtxt<'tcx>, |
f9f354fc | 15 | key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>, |
5e7ed085 | 16 | ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { |
3dfed10e XL |
17 | let (param_env, (did, substs)) = key.into_parts(); |
18 | if let Some(did) = did.as_local() { | |
19 | if let Some(param_did) = tcx.opt_const_param_of(did) { | |
20 | return tcx.resolve_instance_of_const_arg(param_env.and((did, param_did, substs))); | |
21 | } | |
22 | } | |
23 | ||
24 | inner_resolve_instance(tcx, param_env.and((ty::WithOptConstParam::unknown(did), substs))) | |
25 | } | |
f9f354fc | 26 | |
3dfed10e XL |
27 | fn resolve_instance_of_const_arg<'tcx>( |
28 | tcx: TyCtxt<'tcx>, | |
29 | key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>, | |
5e7ed085 | 30 | ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { |
3dfed10e XL |
31 | let (param_env, (did, const_param_did, substs)) = key.into_parts(); |
32 | inner_resolve_instance( | |
33 | tcx, | |
34 | param_env.and(( | |
35 | ty::WithOptConstParam { did: did.to_def_id(), const_param_did: Some(const_param_did) }, | |
36 | substs, | |
37 | )), | |
38 | ) | |
39 | } | |
40 | ||
41 | fn inner_resolve_instance<'tcx>( | |
42 | tcx: TyCtxt<'tcx>, | |
43 | key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>, | |
5e7ed085 | 44 | ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { |
3dfed10e XL |
45 | let (param_env, (def, substs)) = key.into_parts(); |
46 | ||
3dfed10e | 47 | let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) { |
74b04a01 | 48 | debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env); |
9c376795 FG |
49 | resolve_associated_item( |
50 | tcx, | |
51 | def.did, | |
52 | param_env, | |
53 | trait_def_id, | |
54 | tcx.normalize_erasing_regions(param_env, substs), | |
55 | ) | |
74b04a01 | 56 | } else { |
3dfed10e | 57 | let ty = tcx.type_of(def.def_id_for_type_of()); |
9ffffee4 FG |
58 | let item_type = |
59 | tcx.subst_and_normalize_erasing_regions(substs, param_env, ty.skip_binder()); | |
74b04a01 | 60 | |
1b1a35ee | 61 | let def = match *item_type.kind() { |
923072b8 | 62 | ty::FnDef(def_id, ..) if tcx.is_intrinsic(def_id) => { |
74b04a01 | 63 | debug!(" => intrinsic"); |
3dfed10e | 64 | ty::InstanceDef::Intrinsic(def.did) |
74b04a01 | 65 | } |
ba9703b0 XL |
66 | ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => { |
67 | let ty = substs.type_at(0); | |
68 | ||
69 | if ty.needs_drop(tcx, param_env) { | |
3dfed10e | 70 | debug!(" => nontrivial drop glue"); |
1b1a35ee | 71 | match *ty.kind() { |
3dfed10e XL |
72 | ty::Closure(..) |
73 | | ty::Generator(..) | |
74 | | ty::Tuple(..) | |
75 | | ty::Adt(..) | |
76 | | ty::Dynamic(..) | |
77 | | ty::Array(..) | |
78 | | ty::Slice(..) => {} | |
79 | // Drop shims can only be built from ADTs. | |
80 | _ => return Ok(None), | |
74b04a01 | 81 | } |
ba9703b0 | 82 | |
ba9703b0 | 83 | ty::InstanceDef::DropGlue(def_id, Some(ty)) |
74b04a01 | 84 | } else { |
ba9703b0 XL |
85 | debug!(" => trivial drop glue"); |
86 | ty::InstanceDef::DropGlue(def_id, None) | |
74b04a01 XL |
87 | } |
88 | } | |
ba9703b0 XL |
89 | _ => { |
90 | debug!(" => free item"); | |
3dfed10e | 91 | ty::InstanceDef::Item(def) |
ba9703b0 | 92 | } |
74b04a01 | 93 | }; |
f9f354fc | 94 | Ok(Some(Instance { def, substs })) |
74b04a01 | 95 | }; |
6a06907d | 96 | debug!("inner_resolve_instance: result={:?}", result); |
74b04a01 XL |
97 | result |
98 | } | |
99 | ||
100 | fn resolve_associated_item<'tcx>( | |
101 | tcx: TyCtxt<'tcx>, | |
5099ac24 | 102 | trait_item_id: DefId, |
74b04a01 XL |
103 | param_env: ty::ParamEnv<'tcx>, |
104 | trait_id: DefId, | |
105 | rcvr_substs: SubstsRef<'tcx>, | |
5e7ed085 | 106 | ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { |
5099ac24 | 107 | debug!(?trait_item_id, ?param_env, ?trait_id, ?rcvr_substs, "resolve_associated_item"); |
74b04a01 XL |
108 | |
109 | let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); | |
136023e0 | 110 | |
f2b60f7d | 111 | let vtbl = match tcx.codegen_select_candidate((param_env, ty::Binder::dummy(trait_ref))) { |
04454e1e FG |
112 | Ok(vtbl) => vtbl, |
113 | Err(CodegenObligationError::Ambiguity) => { | |
114 | let reported = tcx.sess.delay_span_bug( | |
115 | tcx.def_span(trait_item_id), | |
116 | &format!( | |
f2b60f7d | 117 | "encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \ |
04454e1e | 118 | overflow or prior type error", |
04454e1e FG |
119 | ), |
120 | ); | |
121 | return Err(reported); | |
122 | } | |
123 | Err(CodegenObligationError::Unimplemented) => return Ok(None), | |
124 | Err(CodegenObligationError::FulfillmentError) => return Ok(None), | |
125 | }; | |
74b04a01 XL |
126 | |
127 | // Now that we know which impl is being used, we can dispatch to | |
128 | // the actual function: | |
f9f354fc | 129 | Ok(match vtbl { |
1b1a35ee | 130 | traits::ImplSource::UserDefined(impl_data) => { |
ba9703b0 | 131 | debug!( |
1b1a35ee | 132 | "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}", |
5099ac24 | 133 | param_env, trait_item_id, rcvr_substs, impl_data |
ba9703b0 XL |
134 | ); |
135 | assert!(!rcvr_substs.needs_infer()); | |
136 | assert!(!trait_ref.needs_infer()); | |
74b04a01 | 137 | |
ba9703b0 XL |
138 | let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); |
139 | let trait_def = tcx.trait_def(trait_def_id); | |
140 | let leaf_def = trait_def | |
f9f354fc | 141 | .ancestors(tcx, impl_data.impl_def_id)? |
5099ac24 | 142 | .leaf_def(tcx, trait_item_id) |
ba9703b0 | 143 | .unwrap_or_else(|| { |
5099ac24 | 144 | bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id); |
ba9703b0 | 145 | }); |
2b03887a FG |
146 | let infcx = tcx.infer_ctxt().build(); |
147 | let param_env = param_env.with_reveal_all_normalized(tcx); | |
148 | let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs); | |
149 | let substs = translate_substs( | |
150 | &infcx, | |
151 | param_env, | |
152 | impl_data.impl_def_id, | |
153 | substs, | |
154 | leaf_def.defining_node, | |
155 | ); | |
156 | let substs = infcx.tcx.erase_regions(substs); | |
74b04a01 XL |
157 | |
158 | // Since this is a trait item, we need to see if the item is either a trait default item | |
159 | // or a specialization because we can't resolve those unless we can `Reveal::All`. | |
160 | // NOTE: This should be kept in sync with the similar code in | |
ba9703b0 XL |
161 | // `rustc_trait_selection::traits::project::assemble_candidates_from_impls()`. |
162 | let eligible = if leaf_def.is_final() { | |
163 | // Non-specializable items are always projectable. | |
74b04a01 | 164 | true |
74b04a01 | 165 | } else { |
ba9703b0 XL |
166 | // Only reveal a specializable default if we're past type-checking |
167 | // and the obligation is monomorphic, otherwise passes such as | |
168 | // transmute checking and polymorphic MIR optimizations could | |
169 | // get a result which isn't correct for all monomorphizations. | |
f035d41b | 170 | if param_env.reveal() == Reveal::All { |
ba9703b0 XL |
171 | !trait_ref.still_further_specializable() |
172 | } else { | |
173 | false | |
174 | } | |
74b04a01 XL |
175 | }; |
176 | ||
177 | if !eligible { | |
f9f354fc | 178 | return Ok(None); |
74b04a01 XL |
179 | } |
180 | ||
2b03887a | 181 | // Any final impl is required to define all associated items. |
064997fb | 182 | if !leaf_def.item.defaultness(tcx).has_value() { |
2b03887a FG |
183 | let guard = tcx.sess.delay_span_bug( |
184 | tcx.def_span(leaf_def.item.def_id), | |
185 | "missing value for assoc item in impl", | |
186 | ); | |
187 | return Err(guard); | |
064997fb FG |
188 | } |
189 | ||
fc512014 | 190 | let substs = tcx.erase_regions(substs); |
f9f354fc XL |
191 | |
192 | // Check if we just resolved an associated `const` declaration from | |
193 | // a `trait` to an associated `const` definition in an `impl`, where | |
194 | // the definition in the `impl` has the wrong type (for which an | |
195 | // error has already been/will be emitted elsewhere). | |
5099ac24 FG |
196 | if leaf_def.item.kind == ty::AssocKind::Const |
197 | && trait_item_id != leaf_def.item.def_id | |
2b03887a | 198 | && let Some(leaf_def_item) = leaf_def.item.def_id.as_local() |
f9f354fc | 199 | { |
9c376795 | 200 | tcx.compare_impl_const(( |
2b03887a FG |
201 | leaf_def_item, |
202 | trait_item_id, | |
203 | ))?; | |
f9f354fc XL |
204 | } |
205 | ||
206 | Some(ty::Instance::new(leaf_def.item.def_id, substs)) | |
74b04a01 | 207 | } |
1b1a35ee | 208 | traits::ImplSource::Generator(generator_data) => Some(Instance { |
3dfed10e XL |
209 | def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( |
210 | generator_data.generator_def_id, | |
211 | )), | |
74b04a01 XL |
212 | substs: generator_data.substs, |
213 | }), | |
487cf647 FG |
214 | traits::ImplSource::Future(future_data) => Some(Instance { |
215 | def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( | |
216 | future_data.generator_def_id, | |
217 | )), | |
218 | substs: future_data.substs, | |
219 | }), | |
1b1a35ee | 220 | traits::ImplSource::Closure(closure_data) => { |
487cf647 | 221 | let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap(); |
064997fb | 222 | Instance::resolve_closure( |
74b04a01 XL |
223 | tcx, |
224 | closure_data.closure_def_id, | |
225 | closure_data.substs, | |
226 | trait_closure_kind, | |
064997fb | 227 | ) |
74b04a01 | 228 | } |
1b1a35ee | 229 | traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() { |
3dfed10e | 230 | ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { |
5099ac24 | 231 | def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty), |
ba9703b0 | 232 | substs: rcvr_substs, |
3dfed10e XL |
233 | }), |
234 | _ => None, | |
235 | }, | |
1b1a35ee | 236 | traits::ImplSource::Object(ref data) => { |
923072b8 FG |
237 | if let Some(index) = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id) |
238 | { | |
239 | Some(Instance { | |
240 | def: ty::InstanceDef::Virtual(trait_item_id, index), | |
241 | substs: rcvr_substs, | |
242 | }) | |
243 | } else { | |
244 | None | |
245 | } | |
74b04a01 | 246 | } |
1b1a35ee | 247 | traits::ImplSource::Builtin(..) => { |
353b0b11 FG |
248 | let lang_items = tcx.lang_items(); |
249 | if Some(trait_ref.def_id) == lang_items.clone_trait() { | |
ba9703b0 | 250 | // FIXME(eddyb) use lang items for methods instead of names. |
5099ac24 | 251 | let name = tcx.item_name(trait_item_id); |
ba9703b0 XL |
252 | if name == sym::clone { |
253 | let self_ty = trait_ref.self_ty(); | |
254 | ||
2b03887a | 255 | let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env); |
1b1a35ee | 256 | match self_ty.kind() { |
3dfed10e | 257 | _ if is_copy => (), |
f2b60f7d FG |
258 | ty::Generator(..) |
259 | | ty::GeneratorWitness(..) | |
260 | | ty::Closure(..) | |
261 | | ty::Tuple(..) => {} | |
3dfed10e XL |
262 | _ => return Ok(None), |
263 | }; | |
ba9703b0 XL |
264 | |
265 | Some(Instance { | |
5099ac24 | 266 | def: ty::InstanceDef::CloneShim(trait_item_id, self_ty), |
ba9703b0 XL |
267 | substs: rcvr_substs, |
268 | }) | |
269 | } else { | |
270 | assert_eq!(name, sym::clone_from); | |
271 | ||
272 | // Use the default `fn clone_from` from `trait Clone`. | |
fc512014 | 273 | let substs = tcx.erase_regions(rcvr_substs); |
5099ac24 | 274 | Some(ty::Instance::new(trait_item_id, substs)) |
ba9703b0 | 275 | } |
353b0b11 FG |
276 | } else if Some(trait_ref.def_id) == lang_items.fn_ptr_trait() { |
277 | if lang_items.fn_ptr_addr() == Some(trait_item_id) { | |
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::InstanceDef::FnPtrAddrShim(trait_item_id, self_ty), | |
284 | substs: rcvr_substs, | |
285 | }) | |
286 | } else { | |
287 | tcx.sess.emit_fatal(UnexpectedFnPtrAssociatedItem { | |
288 | span: tcx.def_span(trait_item_id), | |
289 | }) | |
290 | } | |
74b04a01 XL |
291 | } else { |
292 | None | |
293 | } | |
294 | } | |
1b1a35ee XL |
295 | traits::ImplSource::AutoImpl(..) |
296 | | traits::ImplSource::Param(..) | |
297 | | traits::ImplSource::TraitAlias(..) | |
c295e0f8 | 298 | | traits::ImplSource::TraitUpcasting(_) |
2b03887a | 299 | | traits::ImplSource::ConstDestruct(_) => None, |
f9f354fc | 300 | }) |
74b04a01 | 301 | } |
ba9703b0 | 302 | |
f035d41b | 303 | pub fn provide(providers: &mut ty::query::Providers) { |
3dfed10e XL |
304 | *providers = |
305 | ty::query::Providers { resolve_instance, resolve_instance_of_const_arg, ..*providers }; | |
ba9703b0 | 306 | } |