2015-09-14 14:55:56 +03:00
|
|
|
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2016-10-20 06:33:20 +03:00
|
|
|
use ty::{self, Ty, TyCtxt, TypeAndMut};
|
2016-03-22 17:30:57 +02:00
|
|
|
use ty::LvaluePreference::{NoPreference};
|
2015-09-14 14:55:56 +03:00
|
|
|
|
|
|
|
use syntax::ast;
|
2016-06-21 18:08:13 -04:00
|
|
|
use syntax_pos::Span;
|
2015-09-14 14:55:56 +03:00
|
|
|
|
2016-03-29 08:50:44 +03:00
|
|
|
use hir;
|
2015-09-14 14:55:56 +03:00
|
|
|
|
2016-08-31 14:00:29 +03:00
|
|
|
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
2016-10-20 06:33:20 +03:00
|
|
|
pub struct Adjustment<'tcx> {
|
|
|
|
pub kind: Adjust<'tcx>,
|
|
|
|
pub target: Ty<'tcx>
|
2015-09-14 14:55:56 +03:00
|
|
|
}
|
|
|
|
|
2016-10-20 06:33:20 +03:00
|
|
|
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
|
|
|
pub enum Adjust<'tcx> {
|
|
|
|
/// Go from ! to any type.
|
|
|
|
NeverToAny,
|
|
|
|
|
|
|
|
/// Go from a fn-item type to a fn-pointer type.
|
|
|
|
ReifyFnPointer,
|
|
|
|
|
|
|
|
/// Go from a safe fn pointer to an unsafe fn pointer.
|
|
|
|
UnsafeFnPointer,
|
|
|
|
|
2017-04-13 21:27:35 +03:00
|
|
|
/// Go from a non-capturing closure to an fn pointer.
|
2017-02-22 01:24:16 +01:00
|
|
|
ClosureFnPointer,
|
|
|
|
|
2016-10-20 06:33:20 +03:00
|
|
|
/// Go from a mut raw pointer to a const raw pointer.
|
|
|
|
MutToConstPointer,
|
|
|
|
|
|
|
|
/// Represents coercing a pointer to a different kind of pointer - where 'kind'
|
|
|
|
/// here means either or both of raw vs borrowed vs unique and fat vs thin.
|
|
|
|
///
|
|
|
|
/// We transform pointers by following the following steps in order:
|
|
|
|
/// 1. Deref the pointer `self.autoderefs` times (may be 0).
|
|
|
|
/// 2. If `autoref` is `Some(_)`, then take the address and produce either a
|
|
|
|
/// `&` or `*` pointer.
|
|
|
|
/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
|
|
|
|
/// which will do things like convert thin pointers to fat
|
|
|
|
/// pointers, or convert structs containing thin pointers to
|
|
|
|
/// structs containing fat pointers, or convert between fat
|
|
|
|
/// pointers. We don't store the details of how the transform is
|
|
|
|
/// done (in fact, we don't know that, because it might depend on
|
|
|
|
/// the precise type parameters). We just store the target
|
|
|
|
/// type. Trans figures out what has to be done at monomorphization
|
|
|
|
/// time based on the precise source/target type at hand.
|
|
|
|
///
|
|
|
|
/// To make that more concrete, here are some common scenarios:
|
|
|
|
///
|
|
|
|
/// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
|
|
|
|
/// Here the pointer will be dereferenced N times (where a dereference can
|
|
|
|
/// happen to raw or borrowed pointers or any smart pointer which implements
|
|
|
|
/// Deref, including Box<_>). The number of dereferences is given by
|
|
|
|
/// `autoderefs`. It can then be auto-referenced zero or one times, indicated
|
|
|
|
/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
|
|
|
|
/// None.
|
|
|
|
///
|
|
|
|
/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
|
|
|
|
/// with a thin pointer, deref a number of times, unsize the underlying data,
|
|
|
|
/// then autoref. The 'unsize' phase may change a fixed length array to a
|
|
|
|
/// dynamically sized one, a concrete object to a trait object, or statically
|
|
|
|
/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
|
|
|
|
/// represented by:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// Adjust::DerefRef {
|
|
|
|
/// autoderefs: 1, // &[i32; 4] -> [i32; 4]
|
|
|
|
/// autoref: Some(AutoBorrow::Ref), // [i32] -> &[i32]
|
|
|
|
/// unsize: Some([i32]), // [i32; 4] -> [i32]
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
|
|
|
|
/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
|
|
|
|
/// The autoderef and -ref are the same as in the above example, but the type
|
|
|
|
/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
|
|
|
|
/// the underlying conversions from `[i32; 4]` to `[i32]`.
|
|
|
|
///
|
|
|
|
/// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case. In
|
|
|
|
/// that case, we have the pointer we need coming in, so there are no
|
|
|
|
/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
|
|
|
|
/// At some point, of course, `Box` should move out of the compiler, in which
|
|
|
|
/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
|
|
|
|
/// Box<[i32]> is represented by:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// Adjust::DerefRef {
|
|
|
|
/// autoderefs: 0,
|
|
|
|
/// autoref: None,
|
|
|
|
/// unsize: Some(Box<[i32]>),
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
DerefRef {
|
|
|
|
/// Step 1. Apply a number of dereferences, producing an lvalue.
|
|
|
|
autoderefs: usize,
|
|
|
|
|
|
|
|
/// Step 2. Optionally produce a pointer/reference from the value.
|
|
|
|
autoref: Option<AutoBorrow<'tcx>>,
|
|
|
|
|
|
|
|
/// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
|
|
|
|
/// `&[T]`. Note that the source could be a thin or fat pointer.
|
|
|
|
unsize: bool,
|
|
|
|
}
|
2015-09-14 14:55:56 +03:00
|
|
|
}
|
|
|
|
|
2016-10-20 06:33:20 +03:00
|
|
|
impl<'tcx> Adjustment<'tcx> {
|
2015-09-14 14:55:56 +03:00
|
|
|
pub fn is_identity(&self) -> bool {
|
2016-10-20 06:33:20 +03:00
|
|
|
match self.kind {
|
|
|
|
Adjust::NeverToAny => self.target.is_never(),
|
|
|
|
|
|
|
|
Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true,
|
|
|
|
|
|
|
|
Adjust::ReifyFnPointer |
|
|
|
|
Adjust::UnsafeFnPointer |
|
2017-02-22 01:24:16 +01:00
|
|
|
Adjust::ClosureFnPointer |
|
2016-10-20 06:33:20 +03:00
|
|
|
Adjust::MutToConstPointer |
|
|
|
|
Adjust::DerefRef {..} => false,
|
2015-09-14 14:55:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-31 14:00:29 +03:00
|
|
|
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
|
2016-10-20 06:33:20 +03:00
|
|
|
pub enum AutoBorrow<'tcx> {
|
2015-09-14 14:55:56 +03:00
|
|
|
/// Convert from T to &T.
|
2016-10-20 06:33:20 +03:00
|
|
|
Ref(&'tcx ty::Region, hir::Mutability),
|
2015-09-14 14:55:56 +03:00
|
|
|
|
|
|
|
/// Convert from T to *T.
|
2016-10-20 06:33:20 +03:00
|
|
|
RawPtr(hir::Mutability),
|
2015-09-14 14:55:56 +03:00
|
|
|
}
|
|
|
|
|
2017-03-17 16:17:45 -04:00
|
|
|
/// Information for `CoerceUnsized` impls, storing information we
|
|
|
|
/// have computed about the coercion.
|
|
|
|
///
|
|
|
|
/// This struct can be obtained via the `coerce_impl_info` query.
|
|
|
|
/// Demanding this struct also has the side-effect of reporting errors
|
|
|
|
/// for inappropriate impls.
|
|
|
|
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
|
|
|
|
pub struct CoerceUnsizedInfo {
|
|
|
|
/// If this is a "custom coerce" impl, then what kind of custom
|
|
|
|
/// coercion is it? This applies to impls of `CoerceUnsized` for
|
|
|
|
/// structs, primarily, where we store a bit of info about which
|
|
|
|
/// fields need to be coerced.
|
|
|
|
pub custom_kind: Option<CustomCoerceUnsized>
|
|
|
|
}
|
|
|
|
|
2015-09-14 14:55:56 +03:00
|
|
|
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
|
|
|
|
pub enum CustomCoerceUnsized {
|
|
|
|
/// Records the index of the field being coerced.
|
|
|
|
Struct(usize)
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
|
2015-09-14 14:55:56 +03:00
|
|
|
pub fn adjust_for_autoderef<F>(&'tcx self,
|
2016-04-29 06:00:23 +03:00
|
|
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
2015-09-14 14:55:56 +03:00
|
|
|
expr_id: ast::NodeId,
|
|
|
|
expr_span: Span,
|
|
|
|
autoderef: u32, // how many autoderefs so far?
|
|
|
|
mut method_type: F)
|
|
|
|
-> Ty<'tcx> where
|
|
|
|
F: FnMut(ty::MethodCall) -> Option<Ty<'tcx>>,
|
|
|
|
{
|
|
|
|
let method_call = ty::MethodCall::autoderef(expr_id, autoderef);
|
|
|
|
let mut adjusted_ty = self;
|
|
|
|
if let Some(method_ty) = method_type(method_call) {
|
|
|
|
// Method calls always have all late-bound regions
|
|
|
|
// fully instantiated.
|
2016-07-31 22:33:41 +08:00
|
|
|
adjusted_ty = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
|
2015-09-14 14:55:56 +03:00
|
|
|
}
|
|
|
|
match adjusted_ty.builtin_deref(true, NoPreference) {
|
|
|
|
Some(mt) => mt.ty,
|
|
|
|
None => {
|
2016-03-25 18:31:27 +01:00
|
|
|
span_bug!(
|
2015-09-14 14:55:56 +03:00
|
|
|
expr_span,
|
2016-05-24 14:37:11 +03:00
|
|
|
"the {}th autoderef for {} failed: {}",
|
2016-03-25 18:31:27 +01:00
|
|
|
autoderef,
|
2016-05-24 14:37:11 +03:00
|
|
|
expr_id,
|
2016-03-25 18:31:27 +01:00
|
|
|
adjusted_ty);
|
2015-09-14 14:55:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
2016-10-20 06:33:20 +03:00
|
|
|
autoref: Option<AutoBorrow<'tcx>>)
|
2015-09-14 14:55:56 +03:00
|
|
|
-> Ty<'tcx> {
|
|
|
|
match autoref {
|
|
|
|
None => self,
|
2016-10-20 06:33:20 +03:00
|
|
|
Some(AutoBorrow::Ref(r, m)) => {
|
2016-05-03 04:02:41 +03:00
|
|
|
tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m })
|
2015-09-14 14:55:56 +03:00
|
|
|
}
|
2016-10-20 06:33:20 +03:00
|
|
|
Some(AutoBorrow::RawPtr(m)) => {
|
2016-05-03 04:02:41 +03:00
|
|
|
tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m })
|
2015-09-14 14:55:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|