1 // Copyright 2012-2015 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.
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.
11 pub use self::AutoAdjustment
::*;
12 pub use self::AutoRef
::*;
14 use middle
::ty
::{self, Ty, TypeAndMut, TypeFoldable}
;
15 use middle
::ty
::LvaluePreference
::{NoPreference}
;
18 use syntax
::codemap
::Span
;
22 #[derive(Copy, Clone)]
23 pub enum AutoAdjustment
<'tcx
> {
24 AdjustReifyFnPointer
, // go from a fn-item type to a fn-pointer type
25 AdjustUnsafeFnPointer
, // go from a safe fn pointer to an unsafe fn pointer
26 AdjustMutToConstPointer
, // go from a mut raw pointer to a const raw pointer
27 AdjustDerefRef(AutoDerefRef
<'tcx
>),
30 /// Represents coercing a pointer to a different kind of pointer - where 'kind'
31 /// here means either or both of raw vs borrowed vs unique and fat vs thin.
33 /// We transform pointers by following the following steps in order:
34 /// 1. Deref the pointer `self.autoderefs` times (may be 0).
35 /// 2. If `autoref` is `Some(_)`, then take the address and produce either a
36 /// `&` or `*` pointer.
37 /// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
38 /// which will do things like convert thin pointers to fat
39 /// pointers, or convert structs containing thin pointers to
40 /// structs containing fat pointers, or convert between fat
41 /// pointers. We don't store the details of how the transform is
42 /// done (in fact, we don't know that, because it might depend on
43 /// the precise type parameters). We just store the target
44 /// type. Trans figures out what has to be done at monomorphization
45 /// time based on the precise source/target type at hand.
47 /// To make that more concrete, here are some common scenarios:
49 /// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
50 /// Here the pointer will be dereferenced N times (where a dereference can
51 /// happen to raw or borrowed pointers or any smart pointer which implements
52 /// Deref, including Box<_>). The number of dereferences is given by
53 /// `autoderefs`. It can then be auto-referenced zero or one times, indicated
54 /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
57 /// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
58 /// with a thin pointer, deref a number of times, unsize the underlying data,
59 /// then autoref. The 'unsize' phase may change a fixed length array to a
60 /// dynamically sized one, a concrete object to a trait object, or statically
61 /// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
66 /// autoderefs: 1, // &[i32; 4] -> [i32; 4]
67 /// autoref: Some(AutoPtr), // [i32] -> &[i32]
68 /// unsize: Some([i32]), // [i32; 4] -> [i32]
72 /// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
73 /// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
74 /// The autoderef and -ref are the same as in the above example, but the type
75 /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
76 /// the underlying conversions from `[i32; 4]` to `[i32]`.
78 /// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case. In
79 /// that case, we have the pointer we need coming in, so there are no
80 /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
81 /// At some point, of course, `Box` should move out of the compiler, in which
82 /// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
83 /// Box<[i32]> is represented by:
89 /// unsize: Some(Box<[i32]>),
92 #[derive(Copy, Clone)]
93 pub struct AutoDerefRef
<'tcx
> {
94 /// Step 1. Apply a number of dereferences, producing an lvalue.
95 pub autoderefs
: usize,
97 /// Step 2. Optionally produce a pointer/reference from the value.
98 pub autoref
: Option
<AutoRef
<'tcx
>>,
100 /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
101 /// `&[T]`. The stored type is the target pointer type. Note that
102 /// the source could be a thin or fat pointer.
103 pub unsize
: Option
<Ty
<'tcx
>>,
106 impl<'tcx
> AutoAdjustment
<'tcx
> {
107 pub fn is_identity(&self) -> bool
{
109 AdjustReifyFnPointer
|
110 AdjustUnsafeFnPointer
|
111 AdjustMutToConstPointer
=> false,
112 AdjustDerefRef(ref r
) => r
.is_identity(),
116 impl<'tcx
> AutoDerefRef
<'tcx
> {
117 pub fn is_identity(&self) -> bool
{
118 self.autoderefs
== 0 && self.unsize
.is_none() && self.autoref
.is_none()
123 #[derive(Copy, Clone, PartialEq, Debug)]
124 pub enum AutoRef
<'tcx
> {
125 /// Convert from T to &T.
126 AutoPtr(&'tcx ty
::Region
, hir
::Mutability
),
128 /// Convert from T to *T.
129 /// Value to thin pointer.
130 AutoUnsafe(hir
::Mutability
),
133 #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
134 pub enum CustomCoerceUnsized
{
135 /// Records the index of the field being coerced.
139 impl<'tcx
> ty
::TyS
<'tcx
> {
140 /// See `expr_ty_adjusted`
141 pub fn adjust
<F
>(&'tcx
self, cx
: &ty
::ctxt
<'tcx
>,
143 expr_id
: ast
::NodeId
,
144 adjustment
: Option
<&AutoAdjustment
<'tcx
>>,
147 F
: FnMut(ty
::MethodCall
) -> Option
<Ty
<'tcx
>>,
149 if let ty
::TyError
= self.sty
{
153 return match adjustment
{
154 Some(adjustment
) => {
156 AdjustReifyFnPointer
=> {
158 ty
::TyBareFn(Some(_
), b
) => {
163 &format
!("AdjustReifyFnPointer adjustment on non-fn-item: \
169 AdjustUnsafeFnPointer
=> {
171 ty
::TyBareFn(None
, b
) => cx
.safe_to_unsafe_fn_ty(b
),
174 &format
!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: \
181 AdjustMutToConstPointer
=> {
183 ty
::TyRawPtr(mt
) => cx
.mk_ptr(ty
::TypeAndMut
{
185 mutbl
: hir
::MutImmutable
189 &format
!("AdjustMutToConstPointer on non-raw-ptr: \
196 AdjustDerefRef(ref adj
) => {
197 let mut adjusted_ty
= self;
199 if !adjusted_ty
.references_error() {
200 for i
in 0..adj
.autoderefs
{
202 adjusted_ty
.adjust_for_autoderef(cx
,
210 if let Some(target
) = adj
.unsize
{
213 adjusted_ty
.adjust_for_autoref(cx
, adj
.autoref
)
222 pub fn adjust_for_autoderef
<F
>(&'tcx
self,
224 expr_id
: ast
::NodeId
,
226 autoderef
: u32, // how many autoderefs so far?
229 F
: FnMut(ty
::MethodCall
) -> Option
<Ty
<'tcx
>>,
231 let method_call
= ty
::MethodCall
::autoderef(expr_id
, autoderef
);
232 let mut adjusted_ty
= self;
233 if let Some(method_ty
) = method_type(method_call
) {
234 // Method calls always have all late-bound regions
235 // fully instantiated.
236 let fn_ret
= cx
.no_late_bound_regions(&method_ty
.fn_ret()).unwrap();
237 adjusted_ty
= fn_ret
.unwrap();
239 match adjusted_ty
.builtin_deref(true, NoPreference
) {
244 &format
!("the {}th autoderef failed: {}",
252 pub fn adjust_for_autoref(&'tcx
self, cx
: &ty
::ctxt
<'tcx
>,
253 autoref
: Option
<AutoRef
<'tcx
>>)
257 Some(AutoPtr(r
, m
)) => {
258 cx
.mk_ref(r
, TypeAndMut { ty: self, mutbl: m }
)
260 Some(AutoUnsafe(m
)) => {
261 cx
.mk_ptr(TypeAndMut { ty: self, mutbl: m }
)