]>
Commit | Line | Data |
---|---|---|
f9f354fc | 1 | use rustc_errors::ErrorReported; |
3dfed10e | 2 | use rustc_hir::def_id::{DefId, LocalDefId}; |
ba9703b0 XL |
3 | use rustc_infer::infer::TyCtxtInferExt; |
4 | use rustc_middle::ty::subst::SubstsRef; | |
136023e0 | 5 | use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor}; |
3dfed10e | 6 | use rustc_span::{sym, DUMMY_SP}; |
74b04a01 | 7 | use rustc_target::spec::abi::Abi; |
ba9703b0 XL |
8 | use rustc_trait_selection::traits; |
9 | use traits::{translate_substs, Reveal}; | |
74b04a01 | 10 | |
136023e0 XL |
11 | use rustc_data_structures::sso::SsoHashSet; |
12 | use std::collections::btree_map::Entry; | |
13 | use std::collections::BTreeMap; | |
14 | use std::ops::ControlFlow; | |
15 | ||
3dfed10e | 16 | use tracing::debug; |
74b04a01 | 17 | |
136023e0 XL |
18 | // FIXME(#86795): `BoundVarsCollector` here should **NOT** be used |
19 | // outside of `resolve_associated_item`. It's just to address #64494, | |
20 | // #83765, and #85848 which are creating bound types/regions that lose | |
21 | // their `Binder` *unintentionally*. | |
22 | // It's ideal to remove `BoundVarsCollector` and just use | |
23 | // `ty::Binder::*` methods but we use this stopgap until we figure out | |
24 | // the "real" fix. | |
25 | struct BoundVarsCollector<'tcx> { | |
26 | binder_index: ty::DebruijnIndex, | |
27 | vars: BTreeMap<u32, ty::BoundVariableKind>, | |
28 | // We may encounter the same variable at different levels of binding, so | |
29 | // this can't just be `Ty` | |
30 | visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>, | |
31 | } | |
32 | ||
33 | impl<'tcx> BoundVarsCollector<'tcx> { | |
34 | fn new() -> Self { | |
35 | BoundVarsCollector { | |
36 | binder_index: ty::INNERMOST, | |
37 | vars: BTreeMap::new(), | |
38 | visited: SsoHashSet::default(), | |
39 | } | |
40 | } | |
41 | ||
42 | fn into_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx ty::List<ty::BoundVariableKind> { | |
43 | let max = self.vars.iter().map(|(k, _)| *k).max().unwrap_or(0); | |
44 | for i in 0..max { | |
45 | if let None = self.vars.get(&i) { | |
46 | panic!("Unknown variable: {:?}", i); | |
47 | } | |
48 | } | |
49 | ||
50 | tcx.mk_bound_variable_kinds(self.vars.into_iter().map(|(_, v)| v)) | |
51 | } | |
52 | } | |
53 | ||
54 | impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { | |
55 | type BreakTy = (); | |
56 | ||
57 | fn visit_binder<T: TypeFoldable<'tcx>>( | |
58 | &mut self, | |
59 | t: &Binder<'tcx, T>, | |
60 | ) -> ControlFlow<Self::BreakTy> { | |
61 | self.binder_index.shift_in(1); | |
62 | let result = t.super_visit_with(self); | |
63 | self.binder_index.shift_out(1); | |
64 | result | |
65 | } | |
66 | ||
67 | fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { | |
68 | if t.outer_exclusive_binder() < self.binder_index | |
69 | || !self.visited.insert((self.binder_index, t)) | |
70 | { | |
71 | return ControlFlow::CONTINUE; | |
72 | } | |
73 | match *t.kind() { | |
74 | ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { | |
75 | match self.vars.entry(bound_ty.var.as_u32()) { | |
76 | Entry::Vacant(entry) => { | |
77 | entry.insert(ty::BoundVariableKind::Ty(bound_ty.kind)); | |
78 | } | |
79 | Entry::Occupied(entry) => match entry.get() { | |
80 | ty::BoundVariableKind::Ty(_) => {} | |
81 | _ => bug!("Conflicting bound vars"), | |
82 | }, | |
83 | } | |
84 | } | |
85 | ||
86 | _ => (), | |
87 | }; | |
88 | ||
89 | t.super_visit_with(self) | |
90 | } | |
91 | ||
92 | fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { | |
93 | match r { | |
94 | ty::ReLateBound(index, br) if *index == self.binder_index => { | |
95 | match self.vars.entry(br.var.as_u32()) { | |
96 | Entry::Vacant(entry) => { | |
97 | entry.insert(ty::BoundVariableKind::Region(br.kind)); | |
98 | } | |
99 | Entry::Occupied(entry) => match entry.get() { | |
100 | ty::BoundVariableKind::Region(_) => {} | |
101 | _ => bug!("Conflicting bound vars"), | |
102 | }, | |
103 | } | |
104 | } | |
105 | ||
106 | _ => (), | |
107 | }; | |
108 | ||
109 | r.super_visit_with(self) | |
110 | } | |
111 | } | |
112 | ||
6a06907d | 113 | #[instrument(level = "debug", skip(tcx))] |
f9f354fc | 114 | fn resolve_instance<'tcx>( |
74b04a01 | 115 | tcx: TyCtxt<'tcx>, |
f9f354fc XL |
116 | key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>, |
117 | ) -> Result<Option<Instance<'tcx>>, ErrorReported> { | |
3dfed10e XL |
118 | let (param_env, (did, substs)) = key.into_parts(); |
119 | if let Some(did) = did.as_local() { | |
120 | if let Some(param_did) = tcx.opt_const_param_of(did) { | |
121 | return tcx.resolve_instance_of_const_arg(param_env.and((did, param_did, substs))); | |
122 | } | |
123 | } | |
124 | ||
125 | inner_resolve_instance(tcx, param_env.and((ty::WithOptConstParam::unknown(did), substs))) | |
126 | } | |
f9f354fc | 127 | |
3dfed10e XL |
128 | fn resolve_instance_of_const_arg<'tcx>( |
129 | tcx: TyCtxt<'tcx>, | |
130 | key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>, | |
131 | ) -> Result<Option<Instance<'tcx>>, ErrorReported> { | |
132 | let (param_env, (did, const_param_did, substs)) = key.into_parts(); | |
133 | inner_resolve_instance( | |
134 | tcx, | |
135 | param_env.and(( | |
136 | ty::WithOptConstParam { did: did.to_def_id(), const_param_did: Some(const_param_did) }, | |
137 | substs, | |
138 | )), | |
139 | ) | |
140 | } | |
141 | ||
6a06907d | 142 | #[instrument(level = "debug", skip(tcx))] |
3dfed10e XL |
143 | fn inner_resolve_instance<'tcx>( |
144 | tcx: TyCtxt<'tcx>, | |
145 | key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>, | |
146 | ) -> Result<Option<Instance<'tcx>>, ErrorReported> { | |
147 | let (param_env, (def, substs)) = key.into_parts(); | |
148 | ||
3dfed10e | 149 | let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) { |
74b04a01 | 150 | debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env); |
3dfed10e | 151 | let item = tcx.associated_item(def.did); |
74b04a01 XL |
152 | resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) |
153 | } else { | |
3dfed10e | 154 | let ty = tcx.type_of(def.def_id_for_type_of()); |
fc512014 | 155 | let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty); |
74b04a01 | 156 | |
1b1a35ee | 157 | let def = match *item_type.kind() { |
74b04a01 XL |
158 | ty::FnDef(..) |
159 | if { | |
160 | let f = item_type.fn_sig(tcx); | |
161 | f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic | |
162 | } => | |
163 | { | |
164 | debug!(" => intrinsic"); | |
3dfed10e | 165 | ty::InstanceDef::Intrinsic(def.did) |
74b04a01 | 166 | } |
ba9703b0 XL |
167 | ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => { |
168 | let ty = substs.type_at(0); | |
169 | ||
170 | if ty.needs_drop(tcx, param_env) { | |
3dfed10e | 171 | debug!(" => nontrivial drop glue"); |
1b1a35ee | 172 | match *ty.kind() { |
3dfed10e XL |
173 | ty::Closure(..) |
174 | | ty::Generator(..) | |
175 | | ty::Tuple(..) | |
176 | | ty::Adt(..) | |
177 | | ty::Dynamic(..) | |
178 | | ty::Array(..) | |
179 | | ty::Slice(..) => {} | |
180 | // Drop shims can only be built from ADTs. | |
181 | _ => return Ok(None), | |
74b04a01 | 182 | } |
ba9703b0 | 183 | |
ba9703b0 | 184 | ty::InstanceDef::DropGlue(def_id, Some(ty)) |
74b04a01 | 185 | } else { |
ba9703b0 XL |
186 | debug!(" => trivial drop glue"); |
187 | ty::InstanceDef::DropGlue(def_id, None) | |
74b04a01 XL |
188 | } |
189 | } | |
ba9703b0 XL |
190 | _ => { |
191 | debug!(" => free item"); | |
3dfed10e | 192 | ty::InstanceDef::Item(def) |
ba9703b0 | 193 | } |
74b04a01 | 194 | }; |
f9f354fc | 195 | Ok(Some(Instance { def, substs })) |
74b04a01 | 196 | }; |
6a06907d | 197 | debug!("inner_resolve_instance: result={:?}", result); |
74b04a01 XL |
198 | result |
199 | } | |
200 | ||
201 | fn resolve_associated_item<'tcx>( | |
202 | tcx: TyCtxt<'tcx>, | |
203 | trait_item: &ty::AssocItem, | |
204 | param_env: ty::ParamEnv<'tcx>, | |
205 | trait_id: DefId, | |
206 | rcvr_substs: SubstsRef<'tcx>, | |
f9f354fc | 207 | ) -> Result<Option<Instance<'tcx>>, ErrorReported> { |
74b04a01 XL |
208 | let def_id = trait_item.def_id; |
209 | debug!( | |
210 | "resolve_associated_item(trait_item={:?}, \ | |
211 | param_env={:?}, \ | |
212 | trait_id={:?}, \ | |
213 | rcvr_substs={:?})", | |
214 | def_id, param_env, trait_id, rcvr_substs | |
215 | ); | |
216 | ||
217 | let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); | |
136023e0 XL |
218 | |
219 | // See FIXME on `BoundVarsCollector`. | |
220 | let mut bound_vars_collector = BoundVarsCollector::new(); | |
221 | trait_ref.visit_with(&mut bound_vars_collector); | |
222 | let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx)); | |
223 | let vtbl = tcx.codegen_fulfill_obligation((param_env, trait_binder))?; | |
74b04a01 XL |
224 | |
225 | // Now that we know which impl is being used, we can dispatch to | |
226 | // the actual function: | |
f9f354fc | 227 | Ok(match vtbl { |
1b1a35ee | 228 | traits::ImplSource::UserDefined(impl_data) => { |
ba9703b0 | 229 | debug!( |
1b1a35ee | 230 | "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}", |
ba9703b0 XL |
231 | param_env, trait_item, rcvr_substs, impl_data |
232 | ); | |
233 | assert!(!rcvr_substs.needs_infer()); | |
234 | assert!(!trait_ref.needs_infer()); | |
74b04a01 | 235 | |
ba9703b0 XL |
236 | let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); |
237 | let trait_def = tcx.trait_def(trait_def_id); | |
238 | let leaf_def = trait_def | |
f9f354fc | 239 | .ancestors(tcx, impl_data.impl_def_id)? |
ba9703b0 XL |
240 | .leaf_def(tcx, trait_item.ident, trait_item.kind) |
241 | .unwrap_or_else(|| { | |
242 | bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id); | |
243 | }); | |
ba9703b0 XL |
244 | |
245 | let substs = tcx.infer_ctxt().enter(|infcx| { | |
3dfed10e | 246 | let param_env = param_env.with_reveal_all_normalized(tcx); |
ba9703b0 XL |
247 | let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs); |
248 | let substs = translate_substs( | |
249 | &infcx, | |
250 | param_env, | |
251 | impl_data.impl_def_id, | |
252 | substs, | |
253 | leaf_def.defining_node, | |
254 | ); | |
fc512014 | 255 | infcx.tcx.erase_regions(substs) |
ba9703b0 | 256 | }); |
74b04a01 XL |
257 | |
258 | // Since this is a trait item, we need to see if the item is either a trait default item | |
259 | // or a specialization because we can't resolve those unless we can `Reveal::All`. | |
260 | // NOTE: This should be kept in sync with the similar code in | |
ba9703b0 XL |
261 | // `rustc_trait_selection::traits::project::assemble_candidates_from_impls()`. |
262 | let eligible = if leaf_def.is_final() { | |
263 | // Non-specializable items are always projectable. | |
74b04a01 | 264 | true |
74b04a01 | 265 | } else { |
ba9703b0 XL |
266 | // Only reveal a specializable default if we're past type-checking |
267 | // and the obligation is monomorphic, otherwise passes such as | |
268 | // transmute checking and polymorphic MIR optimizations could | |
269 | // get a result which isn't correct for all monomorphizations. | |
f035d41b | 270 | if param_env.reveal() == Reveal::All { |
ba9703b0 XL |
271 | !trait_ref.still_further_specializable() |
272 | } else { | |
273 | false | |
274 | } | |
74b04a01 XL |
275 | }; |
276 | ||
277 | if !eligible { | |
f9f354fc | 278 | return Ok(None); |
74b04a01 XL |
279 | } |
280 | ||
fc512014 | 281 | let substs = tcx.erase_regions(substs); |
f9f354fc XL |
282 | |
283 | // Check if we just resolved an associated `const` declaration from | |
284 | // a `trait` to an associated `const` definition in an `impl`, where | |
285 | // the definition in the `impl` has the wrong type (for which an | |
286 | // error has already been/will be emitted elsewhere). | |
287 | // | |
288 | // NB: this may be expensive, we try to skip it in all the cases where | |
289 | // we know the error would've been caught (e.g. in an upstream crate). | |
290 | // | |
291 | // A better approach might be to just introduce a query (returning | |
292 | // `Result<(), ErrorReported>`) for the check that `rustc_typeck` | |
293 | // performs (i.e. that the definition's type in the `impl` matches | |
294 | // the declaration in the `trait`), so that we can cheaply check | |
295 | // here if it failed, instead of approximating it. | |
296 | if trait_item.kind == ty::AssocKind::Const | |
297 | && trait_item.def_id != leaf_def.item.def_id | |
298 | && leaf_def.item.def_id.is_local() | |
299 | { | |
300 | let normalized_type_of = |def_id, substs| { | |
fc512014 | 301 | tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id)) |
f9f354fc XL |
302 | }; |
303 | ||
304 | let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs); | |
305 | let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs); | |
306 | ||
307 | if original_ty != resolved_ty { | |
308 | let msg = format!( | |
309 | "Instance::resolve: inconsistent associated `const` type: \ | |
310 | was `{}: {}` but resolved to `{}: {}`", | |
311 | tcx.def_path_str_with_substs(trait_item.def_id, rcvr_substs), | |
312 | original_ty, | |
313 | tcx.def_path_str_with_substs(leaf_def.item.def_id, substs), | |
314 | resolved_ty, | |
315 | ); | |
316 | let span = tcx.def_span(leaf_def.item.def_id); | |
317 | tcx.sess.delay_span_bug(span, &msg); | |
318 | ||
319 | return Err(ErrorReported); | |
320 | } | |
321 | } | |
322 | ||
323 | Some(ty::Instance::new(leaf_def.item.def_id, substs)) | |
74b04a01 | 324 | } |
1b1a35ee | 325 | traits::ImplSource::Generator(generator_data) => Some(Instance { |
3dfed10e XL |
326 | def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( |
327 | generator_data.generator_def_id, | |
328 | )), | |
74b04a01 XL |
329 | substs: generator_data.substs, |
330 | }), | |
1b1a35ee | 331 | traits::ImplSource::Closure(closure_data) => { |
74b04a01 XL |
332 | let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); |
333 | Some(Instance::resolve_closure( | |
334 | tcx, | |
335 | closure_data.closure_def_id, | |
336 | closure_data.substs, | |
337 | trait_closure_kind, | |
338 | )) | |
339 | } | |
1b1a35ee | 340 | traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() { |
3dfed10e | 341 | ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { |
ba9703b0 XL |
342 | def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), |
343 | substs: rcvr_substs, | |
3dfed10e XL |
344 | }), |
345 | _ => None, | |
346 | }, | |
1b1a35ee | 347 | traits::ImplSource::Object(ref data) => { |
74b04a01 XL |
348 | let index = traits::get_vtable_index_of_object_method(tcx, data, def_id); |
349 | Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) | |
350 | } | |
1b1a35ee | 351 | traits::ImplSource::Builtin(..) => { |
ba9703b0 XL |
352 | if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() { |
353 | // FIXME(eddyb) use lang items for methods instead of names. | |
354 | let name = tcx.item_name(def_id); | |
355 | if name == sym::clone { | |
356 | let self_ty = trait_ref.self_ty(); | |
357 | ||
3dfed10e | 358 | let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env); |
1b1a35ee | 359 | match self_ty.kind() { |
3dfed10e XL |
360 | _ if is_copy => (), |
361 | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {} | |
362 | _ => return Ok(None), | |
363 | }; | |
ba9703b0 XL |
364 | |
365 | Some(Instance { | |
366 | def: ty::InstanceDef::CloneShim(def_id, self_ty), | |
367 | substs: rcvr_substs, | |
368 | }) | |
369 | } else { | |
370 | assert_eq!(name, sym::clone_from); | |
371 | ||
372 | // Use the default `fn clone_from` from `trait Clone`. | |
fc512014 | 373 | let substs = tcx.erase_regions(rcvr_substs); |
ba9703b0 XL |
374 | Some(ty::Instance::new(def_id, substs)) |
375 | } | |
74b04a01 XL |
376 | } else { |
377 | None | |
378 | } | |
379 | } | |
1b1a35ee XL |
380 | traits::ImplSource::AutoImpl(..) |
381 | | traits::ImplSource::Param(..) | |
382 | | traits::ImplSource::TraitAlias(..) | |
6a06907d XL |
383 | | traits::ImplSource::DiscriminantKind(..) |
384 | | traits::ImplSource::Pointee(..) => None, | |
f9f354fc | 385 | }) |
74b04a01 | 386 | } |
ba9703b0 | 387 | |
f035d41b | 388 | pub fn provide(providers: &mut ty::query::Providers) { |
3dfed10e XL |
389 | *providers = |
390 | ty::query::Providers { resolve_instance, resolve_instance_of_const_arg, ..*providers }; | |
ba9703b0 | 391 | } |