]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/instance.rs
0a49dea7ec1bce319d55da74f211767ddd19edd0
[rust.git] / src / librustc / ty / instance.rs
1 use crate::hir::Unsafety;
2 use crate::hir::def_id::DefId;
3 use crate::ty::{self, Ty, PolyFnSig, TypeFoldable, SubstsRef, TyCtxt};
4 use crate::traits;
5 use rustc_target::spec::abi::Abi;
6 use rustc_macros::HashStable;
7 use crate::util::ppaux;
8
9 use std::fmt;
10 use std::iter;
11
12 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, HashStable)]
13 pub struct Instance<'tcx> {
14     pub def: InstanceDef<'tcx>,
15     pub substs: SubstsRef<'tcx>,
16 }
17
18 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, HashStable)]
19 pub enum InstanceDef<'tcx> {
20     Item(DefId),
21     Intrinsic(DefId),
22
23     /// `<T as Trait>::method` where `method` receives unsizeable `self: Self`.
24     VtableShim(DefId),
25
26     /// `<fn() as FnTrait>::call_*`
27     /// `DefId` is `FnTrait::call_*`
28     FnPtrShim(DefId, Ty<'tcx>),
29
30     /// `<Trait as Trait>::fn`
31     Virtual(DefId, usize),
32
33     /// `<[mut closure] as FnOnce>::call_once`
34     ClosureOnceShim { call_once: DefId },
35
36     /// `drop_in_place::<T>; None` for empty drop glue.
37     DropGlue(DefId, Option<Ty<'tcx>>),
38
39     ///`<T as Clone>::clone` shim.
40     CloneShim(DefId, Ty<'tcx>),
41 }
42
43 impl<'a, 'tcx> Instance<'tcx> {
44     pub fn ty(&self,
45               tcx: TyCtxt<'a, 'tcx, 'tcx>)
46               -> Ty<'tcx>
47     {
48         let ty = tcx.type_of(self.def.def_id());
49         tcx.subst_and_normalize_erasing_regions(
50             self.substs,
51             ty::ParamEnv::reveal_all(),
52             &ty,
53         )
54     }
55
56     fn fn_sig_noadjust(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> PolyFnSig<'tcx> {
57         let ty = self.ty(tcx);
58         match ty.sty {
59             ty::FnDef(..) |
60             // Shims currently have type FnPtr. Not sure this should remain.
61             ty::FnPtr(_) => ty.fn_sig(tcx),
62             ty::Closure(def_id, substs) => {
63                 let sig = substs.closure_sig(def_id, tcx);
64
65                 let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
66                 sig.map_bound(|sig| tcx.mk_fn_sig(
67                     iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
68                     sig.output(),
69                     sig.c_variadic,
70                     sig.unsafety,
71                     sig.abi
72                 ))
73             }
74             ty::Generator(def_id, substs, _) => {
75                 let sig = substs.poly_sig(def_id, tcx);
76
77                 let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
78                 let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
79
80                 let pin_did = tcx.lang_items().pin_type().unwrap();
81                 let pin_adt_ref = tcx.adt_def(pin_did);
82                 let pin_substs = tcx.intern_substs(&[env_ty.into()]);
83                 let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
84
85                 sig.map_bound(|sig| {
86                     let state_did = tcx.lang_items().gen_state().unwrap();
87                     let state_adt_ref = tcx.adt_def(state_did);
88                     let state_substs = tcx.intern_substs(&[
89                         sig.yield_ty.into(),
90                         sig.return_ty.into(),
91                     ]);
92                     let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
93
94                     tcx.mk_fn_sig(iter::once(env_ty),
95                         ret_ty,
96                         false,
97                         Unsafety::Normal,
98                         Abi::Rust
99                     )
100                 })
101             }
102             _ => bug!("unexpected type {:?} in Instance::fn_sig_noadjust", ty)
103         }
104     }
105
106     pub fn fn_sig(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::PolyFnSig<'tcx> {
107         let mut fn_sig = self.fn_sig_noadjust(tcx);
108         if let InstanceDef::VtableShim(..) = self.def {
109             // Modify fn(self, ...) to fn(self: *mut Self, ...)
110             fn_sig = fn_sig.map_bound(|mut fn_sig| {
111                 let mut inputs_and_output = fn_sig.inputs_and_output.to_vec();
112                 inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]);
113                 fn_sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
114                 fn_sig
115             });
116         }
117         fn_sig
118     }
119 }
120
121 impl<'tcx> InstanceDef<'tcx> {
122     #[inline]
123     pub fn def_id(&self) -> DefId {
124         match *self {
125             InstanceDef::Item(def_id) |
126             InstanceDef::VtableShim(def_id) |
127             InstanceDef::FnPtrShim(def_id, _) |
128             InstanceDef::Virtual(def_id, _) |
129             InstanceDef::Intrinsic(def_id, ) |
130             InstanceDef::ClosureOnceShim { call_once: def_id } |
131             InstanceDef::DropGlue(def_id, _) |
132             InstanceDef::CloneShim(def_id, _) => def_id
133         }
134     }
135
136     #[inline]
137     pub fn attrs<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> {
138         tcx.get_attrs(self.def_id())
139     }
140
141     pub fn is_inline<'a>(
142         &self,
143         tcx: TyCtxt<'a, 'tcx, 'tcx>
144     ) -> bool {
145         use crate::hir::map::DefPathData;
146         let def_id = match *self {
147             ty::InstanceDef::Item(def_id) => def_id,
148             ty::InstanceDef::DropGlue(_, Some(_)) => return false,
149             _ => return true
150         };
151         match tcx.def_key(def_id).disambiguated_data.data {
152             DefPathData::StructCtor |
153             DefPathData::EnumVariant(..) |
154             DefPathData::ClosureExpr => true,
155             _ => false
156         }
157     }
158
159     pub fn requires_local<'a>(
160         &self,
161         tcx: TyCtxt<'a, 'tcx, 'tcx>
162     ) -> bool {
163         if self.is_inline(tcx) {
164             return true
165         }
166         if let ty::InstanceDef::DropGlue(..) = *self {
167             // Drop glue wants to be instantiated at every codegen
168             // unit, but without an #[inline] hint. We should make this
169             // available to normal end-users.
170             return true
171         }
172         tcx.codegen_fn_attrs(self.def_id()).requests_inline()
173     }
174 }
175
176 impl<'tcx> fmt::Display for Instance<'tcx> {
177     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178         ppaux::parameterized(f, self.def_id(), self.substs)?;
179         match self.def {
180             InstanceDef::Item(_) => Ok(()),
181             InstanceDef::VtableShim(_) => {
182                 write!(f, " - shim(vtable)")
183             }
184             InstanceDef::Intrinsic(_) => {
185                 write!(f, " - intrinsic")
186             }
187             InstanceDef::Virtual(_, num) => {
188                 write!(f, " - shim(#{})", num)
189             }
190             InstanceDef::FnPtrShim(_, ty) => {
191                 write!(f, " - shim({:?})", ty)
192             }
193             InstanceDef::ClosureOnceShim { .. } => {
194                 write!(f, " - shim")
195             }
196             InstanceDef::DropGlue(_, ty) => {
197                 write!(f, " - shim({:?})", ty)
198             }
199             InstanceDef::CloneShim(_, ty) => {
200                 write!(f, " - shim({:?})", ty)
201             }
202         }
203     }
204 }
205
206 impl<'a, 'b, 'tcx> Instance<'tcx> {
207     pub fn new(def_id: DefId, substs: SubstsRef<'tcx>)
208                -> Instance<'tcx> {
209         assert!(!substs.has_escaping_bound_vars(),
210                 "substs of instance {:?} not normalized for codegen: {:?}",
211                 def_id, substs);
212         Instance { def: InstanceDef::Item(def_id), substs: substs }
213     }
214
215     pub fn mono(tcx: TyCtxt<'a, 'tcx, 'b>, def_id: DefId) -> Instance<'tcx> {
216         Instance::new(def_id, tcx.global_tcx().empty_substs_for_def_id(def_id))
217     }
218
219     #[inline]
220     pub fn def_id(&self) -> DefId {
221         self.def.def_id()
222     }
223
224     /// Resolves a `(def_id, substs)` pair to an (optional) instance -- most commonly,
225     /// this is used to find the precise code that will run for a trait method invocation,
226     /// if known.
227     ///
228     /// Returns `None` if we cannot resolve `Instance` to a specific instance.
229     /// For example, in a context like this,
230     ///
231     /// ```
232     /// fn foo<T: Debug>(t: T) { ... }
233     /// ```
234     ///
235     /// trying to resolve `Debug::fmt` applied to `T` will yield `None`, because we do not
236     /// know what code ought to run. (Note that this setting is also affected by the
237     /// `RevealMode` in the parameter environment.)
238     ///
239     /// Presuming that coherence and type-check have succeeded, if this method is invoked
240     /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
241     /// `Some`.
242     pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>,
243                    param_env: ty::ParamEnv<'tcx>,
244                    def_id: DefId,
245                    substs: SubstsRef<'tcx>) -> Option<Instance<'tcx>> {
246         debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
247         let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
248             debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
249             let item = tcx.associated_item(def_id);
250             resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
251         } else {
252             let ty = tcx.type_of(def_id);
253             let item_type = tcx.subst_and_normalize_erasing_regions(
254                 substs,
255                 param_env,
256                 &ty,
257             );
258
259             let def = match item_type.sty {
260                 ty::FnDef(..) if {
261                     let f = item_type.fn_sig(tcx);
262                     f.abi() == Abi::RustIntrinsic ||
263                         f.abi() == Abi::PlatformIntrinsic
264                 } =>
265                 {
266                     debug!(" => intrinsic");
267                     ty::InstanceDef::Intrinsic(def_id)
268                 }
269                 _ => {
270                     if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
271                         let ty = substs.type_at(0);
272                         if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
273                             debug!(" => nontrivial drop glue");
274                             ty::InstanceDef::DropGlue(def_id, Some(ty))
275                         } else {
276                             debug!(" => trivial drop glue");
277                             ty::InstanceDef::DropGlue(def_id, None)
278                         }
279                     } else {
280                         debug!(" => free item");
281                         ty::InstanceDef::Item(def_id)
282                     }
283                 }
284             };
285             Some(Instance {
286                 def: def,
287                 substs: substs
288             })
289         };
290         debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result);
291         result
292     }
293
294     pub fn resolve_for_vtable(tcx: TyCtxt<'a, 'tcx, 'tcx>,
295                               param_env: ty::ParamEnv<'tcx>,
296                               def_id: DefId,
297                               substs: SubstsRef<'tcx>) -> Option<Instance<'tcx>> {
298         debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
299         let fn_sig = tcx.fn_sig(def_id);
300         let is_vtable_shim =
301             fn_sig.inputs().skip_binder().len() > 0 && fn_sig.input(0).skip_binder().is_self();
302         if is_vtable_shim {
303             debug!(" => associated item with unsizeable self: Self");
304             Some(Instance {
305                 def: InstanceDef::VtableShim(def_id),
306                 substs,
307             })
308         } else {
309             Instance::resolve(tcx, param_env, def_id, substs)
310         }
311     }
312
313     pub fn resolve_closure(
314         tcx: TyCtxt<'a, 'tcx, 'tcx>,
315         def_id: DefId,
316         substs: ty::ClosureSubsts<'tcx>,
317         requested_kind: ty::ClosureKind)
318         -> Instance<'tcx>
319     {
320         let actual_kind = substs.closure_kind(def_id, tcx);
321
322         match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
323             Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
324             _ => Instance::new(def_id, substs.substs)
325         }
326     }
327
328     pub fn is_vtable_shim(&self) -> bool {
329         if let InstanceDef::VtableShim(..) = self.def {
330             true
331         } else {
332             false
333         }
334     }
335 }
336
337 fn resolve_associated_item<'a, 'tcx>(
338     tcx: TyCtxt<'a, 'tcx, 'tcx>,
339     trait_item: &ty::AssociatedItem,
340     param_env: ty::ParamEnv<'tcx>,
341     trait_id: DefId,
342     rcvr_substs: SubstsRef<'tcx>,
343 ) -> Option<Instance<'tcx>> {
344     let def_id = trait_item.def_id;
345     debug!("resolve_associated_item(trait_item={:?}, \
346             param_env={:?}, \
347             trait_id={:?}, \
348             rcvr_substs={:?})",
349             def_id, param_env, trait_id, rcvr_substs);
350
351     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
352     let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref)));
353
354     // Now that we know which impl is being used, we can dispatch to
355     // the actual function:
356     match vtbl {
357         traits::VtableImpl(impl_data) => {
358             let (def_id, substs) = traits::find_associated_item(
359                 tcx, param_env, trait_item, rcvr_substs, &impl_data);
360             let substs = tcx.erase_regions(&substs);
361             Some(ty::Instance::new(def_id, substs))
362         }
363         traits::VtableGenerator(generator_data) => {
364             Some(Instance {
365                 def: ty::InstanceDef::Item(generator_data.generator_def_id),
366                 substs: generator_data.substs.substs
367             })
368         }
369         traits::VtableClosure(closure_data) => {
370             let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap();
371             Some(Instance::resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs,
372                                            trait_closure_kind))
373         }
374         traits::VtableFnPointer(ref data) => {
375             Some(Instance {
376                 def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
377                 substs: rcvr_substs
378             })
379         }
380         traits::VtableObject(ref data) => {
381             let index = tcx.get_vtable_index_of_object_method(data, def_id);
382             Some(Instance {
383                 def: ty::InstanceDef::Virtual(def_id, index),
384                 substs: rcvr_substs
385             })
386         }
387         traits::VtableBuiltin(..) => {
388             if tcx.lang_items().clone_trait().is_some() {
389                 Some(Instance {
390                     def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()),
391                     substs: rcvr_substs
392                 })
393             } else {
394                 None
395             }
396         }
397         traits::VtableAutoImpl(..) |
398         traits::VtableParam(..) |
399         traits::VtableTraitAlias(..) => None
400     }
401 }
402
403 fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind,
404                                         trait_closure_kind: ty::ClosureKind)
405     -> Result<bool, ()>
406 {
407     match (actual_closure_kind, trait_closure_kind) {
408         (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
409             (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
410             (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
411                 // No adapter needed.
412                 Ok(false)
413             }
414         (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
415             // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
416             // `fn(&mut self, ...)`. In fact, at codegen time, these are
417             // basically the same thing, so we can just return llfn.
418             Ok(false)
419         }
420         (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
421             (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
422                 // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
423                 // self, ...)`.  We want a `fn(self, ...)`. We can produce
424                 // this by doing something like:
425                 //
426                 //     fn call_once(self, ...) { call_mut(&self, ...) }
427                 //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
428                 //
429                 // These are both the same at codegen time.
430                 Ok(true)
431         }
432         (ty::ClosureKind::FnMut, _) |
433         (ty::ClosureKind::FnOnce, _) => Err(())
434     }
435 }
436
437 fn fn_once_adapter_instance<'a, 'tcx>(
438     tcx: TyCtxt<'a, 'tcx, 'tcx>,
439     closure_did: DefId,
440     substs: ty::ClosureSubsts<'tcx>)
441     -> Instance<'tcx>
442 {
443     debug!("fn_once_adapter_shim({:?}, {:?})",
444            closure_did,
445            substs);
446     let fn_once = tcx.lang_items().fn_once_trait().unwrap();
447     let call_once = tcx.associated_items(fn_once)
448         .find(|it| it.kind == ty::AssociatedKind::Method)
449         .unwrap().def_id;
450     let def = ty::InstanceDef::ClosureOnceShim { call_once };
451
452     let self_ty = tcx.mk_closure(closure_did, substs);
453
454     let sig = substs.closure_sig(closure_did, tcx);
455     let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
456     assert_eq!(sig.inputs().len(), 1);
457     let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
458
459     debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
460     Instance { def, substs }
461 }