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 use ty
::{self, Ty, TyCtxt, TypeAndMut}
;
12 use ty
::LvaluePreference
::{NoPreference}
;
19 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
20 pub struct Adjustment
<'tcx
> {
21 pub kind
: Adjust
<'tcx
>,
25 #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
26 pub enum Adjust
<'tcx
> {
27 /// Go from ! to any type.
30 /// Go from a fn-item type to a fn-pointer type.
33 /// Go from a safe fn pointer to an unsafe fn pointer.
36 // Go from a non-capturing closure to an fn pointer.
39 /// Go from a mut raw pointer to a const raw pointer.
42 /// Represents coercing a pointer to a different kind of pointer - where 'kind'
43 /// here means either or both of raw vs borrowed vs unique and fat vs thin.
45 /// We transform pointers by following the following steps in order:
46 /// 1. Deref the pointer `self.autoderefs` times (may be 0).
47 /// 2. If `autoref` is `Some(_)`, then take the address and produce either a
48 /// `&` or `*` pointer.
49 /// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
50 /// which will do things like convert thin pointers to fat
51 /// pointers, or convert structs containing thin pointers to
52 /// structs containing fat pointers, or convert between fat
53 /// pointers. We don't store the details of how the transform is
54 /// done (in fact, we don't know that, because it might depend on
55 /// the precise type parameters). We just store the target
56 /// type. Trans figures out what has to be done at monomorphization
57 /// time based on the precise source/target type at hand.
59 /// To make that more concrete, here are some common scenarios:
61 /// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
62 /// Here the pointer will be dereferenced N times (where a dereference can
63 /// happen to raw or borrowed pointers or any smart pointer which implements
64 /// Deref, including Box<_>). The number of dereferences is given by
65 /// `autoderefs`. It can then be auto-referenced zero or one times, indicated
66 /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
69 /// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
70 /// with a thin pointer, deref a number of times, unsize the underlying data,
71 /// then autoref. The 'unsize' phase may change a fixed length array to a
72 /// dynamically sized one, a concrete object to a trait object, or statically
73 /// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
77 /// Adjust::DerefRef {
78 /// autoderefs: 1, // &[i32; 4] -> [i32; 4]
79 /// autoref: Some(AutoBorrow::Ref), // [i32] -> &[i32]
80 /// unsize: Some([i32]), // [i32; 4] -> [i32]
84 /// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
85 /// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
86 /// The autoderef and -ref are the same as in the above example, but the type
87 /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
88 /// the underlying conversions from `[i32; 4]` to `[i32]`.
90 /// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case. In
91 /// that case, we have the pointer we need coming in, so there are no
92 /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
93 /// At some point, of course, `Box` should move out of the compiler, in which
94 /// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
95 /// Box<[i32]> is represented by:
98 /// Adjust::DerefRef {
101 /// unsize: Some(Box<[i32]>),
105 /// Step 1. Apply a number of dereferences, producing an lvalue.
108 /// Step 2. Optionally produce a pointer/reference from the value.
109 autoref
: Option
<AutoBorrow
<'tcx
>>,
111 /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
112 /// `&[T]`. Note that the source could be a thin or fat pointer.
117 impl<'tcx
> Adjustment
<'tcx
> {
118 pub fn is_identity(&self) -> bool
{
120 Adjust
::NeverToAny
=> self.target
.is_never(),
122 Adjust
::DerefRef { autoderefs: 0, autoref: None, unsize: false }
=> true,
124 Adjust
::ReifyFnPointer
|
125 Adjust
::UnsafeFnPointer
|
126 Adjust
::ClosureFnPointer
|
127 Adjust
::MutToConstPointer
|
128 Adjust
::DerefRef {..}
=> false,
133 #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
134 pub enum AutoBorrow
<'tcx
> {
135 /// Convert from T to &T.
136 Ref(&'tcx ty
::Region
, hir
::Mutability
),
138 /// Convert from T to *T.
139 RawPtr(hir
::Mutability
),
142 #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
143 pub enum CustomCoerceUnsized
{
144 /// Records the index of the field being coerced.
148 impl<'a
, 'gcx
, 'tcx
> ty
::TyS
<'tcx
> {
149 pub fn adjust_for_autoderef
<F
>(&'tcx
self,
150 tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>,
151 expr_id
: ast
::NodeId
,
153 autoderef
: u32, // how many autoderefs so far?
156 F
: FnMut(ty
::MethodCall
) -> Option
<Ty
<'tcx
>>,
158 let method_call
= ty
::MethodCall
::autoderef(expr_id
, autoderef
);
159 let mut adjusted_ty
= self;
160 if let Some(method_ty
) = method_type(method_call
) {
161 // Method calls always have all late-bound regions
162 // fully instantiated.
163 adjusted_ty
= tcx
.no_late_bound_regions(&method_ty
.fn_ret()).unwrap();
165 match adjusted_ty
.builtin_deref(true, NoPreference
) {
170 "the {}th autoderef for {} failed: {}",
178 pub fn adjust_for_autoref(&'tcx
self, tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>,
179 autoref
: Option
<AutoBorrow
<'tcx
>>)
183 Some(AutoBorrow
::Ref(r
, m
)) => {
184 tcx
.mk_ref(r
, TypeAndMut { ty: self, mutbl: m }
)
186 Some(AutoBorrow
::RawPtr(m
)) => {
187 tcx
.mk_ptr(TypeAndMut { ty: self, mutbl: m }
)