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