]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/monomorphize/mod.rs
Simplify
[rust.git] / src / librustc_mir / monomorphize / mod.rs
1 // Copyright 2012-2014 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 rustc::hir::def_id::DefId;
12 use rustc::middle::lang_items::DropInPlaceFnLangItem;
13 use rustc::traits;
14 use rustc::ty::adjustment::CustomCoerceUnsized;
15 use rustc::ty::{self, Ty, TyCtxt};
16
17 pub use rustc::ty::Instance;
18 pub use self::item::{MonoItem, MonoItemExt};
19
20 pub mod collector;
21 pub mod item;
22 pub mod partitioning;
23
24 #[inline(never)] // give this a place in the profiler
25 pub fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mono_items: I)
26     where I: Iterator<Item=&'a MonoItem<'tcx>>
27 {
28     let mut symbols: Vec<_> = mono_items.map(|mono_item| {
29         (mono_item, mono_item.symbol_name(tcx))
30     }).collect();
31
32     symbols.sort_by_key(|sym| sym.1);
33
34     for pair in symbols.windows(2) {
35         let sym1 = &pair[0].1;
36         let sym2 = &pair[1].1;
37
38         if sym1 == sym2 {
39             let mono_item1 = pair[0].0;
40             let mono_item2 = pair[1].0;
41
42             let span1 = mono_item1.local_span(tcx);
43             let span2 = mono_item2.local_span(tcx);
44
45             // Deterministically select one of the spans for error reporting
46             let span = match (span1, span2) {
47                 (Some(span1), Some(span2)) => {
48                     Some(if span1.lo().0 > span2.lo().0 {
49                         span1
50                     } else {
51                         span2
52                     })
53                 }
54                 (span1, span2) => span1.or(span2),
55             };
56
57             let error_message = format!("symbol `{}` is already defined", sym1);
58
59             if let Some(span) = span {
60                 tcx.sess.span_fatal(span, &error_message)
61             } else {
62                 tcx.sess.fatal(&error_message)
63             }
64         }
65     }
66 }
67
68 fn fn_once_adapter_instance<'a, 'tcx>(
69     tcx: TyCtxt<'a, 'tcx, 'tcx>,
70     closure_did: DefId,
71     substs: ty::ClosureSubsts<'tcx>,
72     ) -> Instance<'tcx> {
73     debug!("fn_once_adapter_shim({:?}, {:?})",
74            closure_did,
75            substs);
76     let fn_once = tcx.lang_items().fn_once_trait().unwrap();
77     let call_once = tcx.associated_items(fn_once)
78         .find(|it| it.kind == ty::AssociatedKind::Method)
79         .unwrap().def_id;
80     let def = ty::InstanceDef::ClosureOnceShim { call_once };
81
82     let self_ty = tcx.mk_closure(closure_did, substs);
83
84     let sig = substs.closure_sig(closure_did, tcx);
85     let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
86     assert_eq!(sig.inputs().len(), 1);
87     let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
88
89     debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
90     Instance { def, substs }
91 }
92
93 fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind,
94                               trait_closure_kind: ty::ClosureKind)
95                               -> Result<bool, ()>
96 {
97     match (actual_closure_kind, trait_closure_kind) {
98         (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
99         (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
100         (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
101             // No adapter needed.
102            Ok(false)
103         }
104         (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
105             // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
106             // `fn(&mut self, ...)`. In fact, at codegen time, these are
107             // basically the same thing, so we can just return llfn.
108             Ok(false)
109         }
110         (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
111         (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
112             // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
113             // self, ...)`.  We want a `fn(self, ...)`. We can produce
114             // this by doing something like:
115             //
116             //     fn call_once(self, ...) { call_mut(&self, ...) }
117             //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
118             //
119             // These are both the same at codegen time.
120             Ok(true)
121         }
122         _ => Err(()),
123     }
124 }
125
126 pub fn resolve_closure<'a, 'tcx> (
127     tcx: TyCtxt<'a, 'tcx, 'tcx>,
128     def_id: DefId,
129     substs: ty::ClosureSubsts<'tcx>,
130     requested_kind: ty::ClosureKind)
131     -> Instance<'tcx>
132 {
133     let actual_kind = substs.closure_kind(def_id, tcx);
134
135     match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
136         Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
137         _ => Instance::new(def_id, substs.substs)
138     }
139 }
140
141 pub fn resolve_drop_in_place<'a, 'tcx>(
142     tcx: TyCtxt<'a, 'tcx, 'tcx>,
143     ty: Ty<'tcx>)
144     -> ty::Instance<'tcx>
145 {
146     let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
147     let substs = tcx.intern_substs(&[ty.into()]);
148     Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap()
149 }
150
151 pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
152                                            source_ty: Ty<'tcx>,
153                                            target_ty: Ty<'tcx>)
154                                            -> CustomCoerceUnsized {
155     let def_id = tcx.lang_items().coerce_unsized_trait().unwrap();
156
157     let trait_ref = ty::Binder::bind(ty::TraitRef {
158         def_id: def_id,
159         substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()])
160     });
161
162     match tcx.codegen_fulfill_obligation( (ty::ParamEnv::reveal_all(), trait_ref)) {
163         traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
164             tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap()
165         }
166         vtable => {
167             bug!("invalid CoerceUnsized vtable: {:?}", vtable);
168         }
169     }
170 }