]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/instance.rs
Account for --remap-path-prefix in save-analysis
[rust.git] / src / librustc / ty / instance.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use hir::def_id::DefId;
12 use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
13 use traits;
14 use rustc_target::spec::abi::Abi;
15 use util::ppaux;
16
17 use std::fmt;
18
19 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
20 pub struct Instance<'tcx> {
21     pub def: InstanceDef<'tcx>,
22     pub substs: &'tcx Substs<'tcx>,
23 }
24
25 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
26 pub enum InstanceDef<'tcx> {
27     Item(DefId),
28     Intrinsic(DefId),
29
30     /// \<fn() as FnTrait>::call_*
31     /// def-id is FnTrait::call_*
32     FnPtrShim(DefId, Ty<'tcx>),
33
34     /// <Trait as Trait>::fn
35     Virtual(DefId, usize),
36
37     /// <[mut closure] as FnOnce>::call_once
38     ClosureOnceShim { call_once: DefId },
39
40     /// drop_in_place::<T>; None for empty drop glue.
41     DropGlue(DefId, Option<Ty<'tcx>>),
42
43     ///`<T as Clone>::clone` shim.
44     CloneShim(DefId, Ty<'tcx>),
45 }
46
47 impl<'a, 'tcx> Instance<'tcx> {
48     pub fn ty(&self,
49               tcx: TyCtxt<'a, 'tcx, 'tcx>)
50               -> Ty<'tcx>
51     {
52         let ty = tcx.type_of(self.def.def_id());
53         tcx.subst_and_normalize_erasing_regions(
54             self.substs,
55             ty::ParamEnv::reveal_all(),
56             &ty,
57         )
58     }
59 }
60
61 impl<'tcx> InstanceDef<'tcx> {
62     #[inline]
63     pub fn def_id(&self) -> DefId {
64         match *self {
65             InstanceDef::Item(def_id) |
66             InstanceDef::FnPtrShim(def_id, _) |
67             InstanceDef::Virtual(def_id, _) |
68             InstanceDef::Intrinsic(def_id, ) |
69             InstanceDef::ClosureOnceShim { call_once: def_id } |
70             InstanceDef::DropGlue(def_id, _) |
71             InstanceDef::CloneShim(def_id, _) => def_id
72         }
73     }
74
75     #[inline]
76     pub fn attrs<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> {
77         tcx.get_attrs(self.def_id())
78     }
79
80     pub fn is_inline<'a>(
81         &self,
82         tcx: TyCtxt<'a, 'tcx, 'tcx>
83     ) -> bool {
84         use hir::map::DefPathData;
85         let def_id = match *self {
86             ty::InstanceDef::Item(def_id) => def_id,
87             ty::InstanceDef::DropGlue(_, Some(_)) => return false,
88             _ => return true
89         };
90         match tcx.def_key(def_id).disambiguated_data.data {
91             DefPathData::StructCtor |
92             DefPathData::EnumVariant(..) |
93             DefPathData::ClosureExpr => true,
94             _ => false
95         }
96     }
97
98     pub fn requires_local<'a>(
99         &self,
100         tcx: TyCtxt<'a, 'tcx, 'tcx>
101     ) -> bool {
102         if self.is_inline(tcx) {
103             return true
104         }
105         if let ty::InstanceDef::DropGlue(..) = *self {
106             // Drop glue wants to be instantiated at every codegen
107             // unit, but without an #[inline] hint. We should make this
108             // available to normal end-users.
109             return true
110         }
111         let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id());
112         codegen_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id())
113     }
114 }
115
116 impl<'tcx> fmt::Display for Instance<'tcx> {
117     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118         ppaux::parameterized(f, self.substs, self.def_id(), &[])?;
119         match self.def {
120             InstanceDef::Item(_) => Ok(()),
121             InstanceDef::Intrinsic(_) => {
122                 write!(f, " - intrinsic")
123             }
124             InstanceDef::Virtual(_, num) => {
125                 write!(f, " - shim(#{})", num)
126             }
127             InstanceDef::FnPtrShim(_, ty) => {
128                 write!(f, " - shim({:?})", ty)
129             }
130             InstanceDef::ClosureOnceShim { .. } => {
131                 write!(f, " - shim")
132             }
133             InstanceDef::DropGlue(_, ty) => {
134                 write!(f, " - shim({:?})", ty)
135             }
136             InstanceDef::CloneShim(_, ty) => {
137                 write!(f, " - shim({:?})", ty)
138             }
139         }
140     }
141 }
142
143 impl<'a, 'b, 'tcx> Instance<'tcx> {
144     pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
145                -> Instance<'tcx> {
146         assert!(!substs.has_escaping_regions(),
147                 "substs of instance {:?} not normalized for codegen: {:?}",
148                 def_id, substs);
149         Instance { def: InstanceDef::Item(def_id), substs: substs }
150     }
151
152     pub fn mono(tcx: TyCtxt<'a, 'tcx, 'b>, def_id: DefId) -> Instance<'tcx> {
153         Instance::new(def_id, tcx.global_tcx().empty_substs_for_def_id(def_id))
154     }
155
156     #[inline]
157     pub fn def_id(&self) -> DefId {
158         self.def.def_id()
159     }
160
161     /// Resolve a (def_id, substs) pair to an (optional) instance -- most commonly,
162     /// this is used to find the precise code that will run for a trait method invocation,
163     /// if known.
164     ///
165     /// Returns `None` if we cannot resolve `Instance` to a specific instance.
166     /// For example, in a context like this,
167     ///
168     /// ```
169     /// fn foo<T: Debug>(t: T) { ... }
170     /// ```
171     ///
172     /// trying to resolve `Debug::fmt` applied to `T` will yield `None`, because we do not
173     /// know what code ought to run. (Note that this setting is also affected by the
174     /// `RevealMode` in the parameter environment.)
175     ///
176     /// Presuming that coherence and type-check have succeeded, if this method is invoked
177     /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
178     /// `Some`.
179     pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>,
180                    param_env: ty::ParamEnv<'tcx>,
181                    def_id: DefId,
182                    substs: &'tcx Substs<'tcx>) -> Option<Instance<'tcx>> {
183         debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
184         let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
185             debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
186             let item = tcx.associated_item(def_id);
187             resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
188         } else {
189             let ty = tcx.type_of(def_id);
190             let item_type = tcx.subst_and_normalize_erasing_regions(
191                 substs,
192                 param_env,
193                 &ty,
194             );
195
196             let def = match item_type.sty {
197                 ty::TyFnDef(..) if {
198                     let f = item_type.fn_sig(tcx);
199                     f.abi() == Abi::RustIntrinsic ||
200                         f.abi() == Abi::PlatformIntrinsic
201                 } =>
202                 {
203                     debug!(" => intrinsic");
204                     ty::InstanceDef::Intrinsic(def_id)
205                 }
206                 _ => {
207                     if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
208                         let ty = substs.type_at(0);
209                         if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
210                             debug!(" => nontrivial drop glue");
211                             ty::InstanceDef::DropGlue(def_id, Some(ty))
212                         } else {
213                             debug!(" => trivial drop glue");
214                             ty::InstanceDef::DropGlue(def_id, None)
215                         }
216                     } else {
217                         debug!(" => free item");
218                         ty::InstanceDef::Item(def_id)
219                     }
220                 }
221             };
222             Some(Instance {
223                 def: def,
224                 substs: substs
225             })
226         };
227         debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result);
228         result
229     }
230
231     pub fn resolve_closure(
232                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
233                     def_id: DefId,
234                     substs: ty::ClosureSubsts<'tcx>,
235                     requested_kind: ty::ClosureKind)
236     -> Instance<'tcx>
237     {
238         let actual_kind = substs.closure_kind(def_id, tcx);
239
240         match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
241             Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
242             _ => Instance::new(def_id, substs.substs)
243         }
244     }
245 }
246
247 fn resolve_associated_item<'a, 'tcx>(
248     tcx: TyCtxt<'a, 'tcx, 'tcx>,
249     trait_item: &ty::AssociatedItem,
250     param_env: ty::ParamEnv<'tcx>,
251     trait_id: DefId,
252     rcvr_substs: &'tcx Substs<'tcx>,
253 ) -> Option<Instance<'tcx>> {
254     let def_id = trait_item.def_id;
255     debug!("resolve_associated_item(trait_item={:?}, \
256                                     trait_id={:?}, \
257            rcvr_substs={:?})",
258            def_id, trait_id, rcvr_substs);
259
260     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
261     let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref)));
262
263     // Now that we know which impl is being used, we can dispatch to
264     // the actual function:
265     match vtbl {
266         traits::VtableImpl(impl_data) => {
267             let (def_id, substs) = traits::find_associated_item(
268                 tcx, trait_item, rcvr_substs, &impl_data);
269             let substs = tcx.erase_regions(&substs);
270             Some(ty::Instance::new(def_id, substs))
271         }
272         traits::VtableGenerator(generator_data) => {
273             Some(Instance {
274                 def: ty::InstanceDef::Item(generator_data.generator_def_id),
275                 substs: generator_data.substs.substs
276             })
277         }
278         traits::VtableClosure(closure_data) => {
279             let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap();
280             Some(Instance::resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs,
281                                  trait_closure_kind))
282         }
283         traits::VtableFnPointer(ref data) => {
284             Some(Instance {
285                 def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
286                 substs: rcvr_substs
287             })
288         }
289         traits::VtableObject(ref data) => {
290             let index = tcx.get_vtable_index_of_object_method(data, def_id);
291             Some(Instance {
292                 def: ty::InstanceDef::Virtual(def_id, index),
293                 substs: rcvr_substs
294             })
295         }
296         traits::VtableBuiltin(..) => {
297             if let Some(_) = tcx.lang_items().clone_trait() {
298                 Some(Instance {
299                     def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()),
300                     substs: rcvr_substs
301                 })
302             } else {
303                 None
304             }
305         }
306         traits::VtableAutoImpl(..) | traits::VtableParam(..) => None
307     }
308 }
309
310 fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind,
311                               trait_closure_kind: ty::ClosureKind)
312     -> Result<bool, ()>
313 {
314     match (actual_closure_kind, trait_closure_kind) {
315         (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
316             (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
317             (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
318                 // No adapter needed.
319                 Ok(false)
320             }
321         (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
322             // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
323             // `fn(&mut self, ...)`. In fact, at codegen time, these are
324             // basically the same thing, so we can just return llfn.
325             Ok(false)
326         }
327         (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
328             (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
329                 // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
330                 // self, ...)`.  We want a `fn(self, ...)`. We can produce
331                 // this by doing something like:
332                 //
333                 //     fn call_once(self, ...) { call_mut(&self, ...) }
334                 //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
335                 //
336                 // These are both the same at codegen time.
337                 Ok(true)
338         }
339         (ty::ClosureKind::FnMut, _) |
340         (ty::ClosureKind::FnOnce, _) => Err(())
341     }
342 }
343
344 fn fn_once_adapter_instance<'a, 'tcx>(
345                             tcx: TyCtxt<'a, 'tcx, 'tcx>,
346                             closure_did: DefId,
347                             substs: ty::ClosureSubsts<'tcx>,
348                             ) -> Instance<'tcx> {
349     debug!("fn_once_adapter_shim({:?}, {:?})",
350     closure_did,
351     substs);
352     let fn_once = tcx.lang_items().fn_once_trait().unwrap();
353     let call_once = tcx.associated_items(fn_once)
354         .find(|it| it.kind == ty::AssociatedKind::Method)
355         .unwrap().def_id;
356     let def = ty::InstanceDef::ClosureOnceShim { call_once };
357
358     let self_ty = tcx.mk_closure(closure_did, substs);
359
360     let sig = substs.closure_sig(closure_did, tcx);
361     let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
362     assert_eq!(sig.inputs().len(), 1);
363     let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
364
365     debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
366     Instance { def, substs }
367 }