rustc: record the target type of every adjustment.
This commit is contained in:
parent
6a8d131e5d
commit
0d7201ef46
29 changed files with 421 additions and 581 deletions
|
|
@ -374,7 +374,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
let method_call = ty::MethodCall::expr(call_expr.id);
|
||||
let fn_ty = match self.tcx.tables().method_map.get(&method_call) {
|
||||
Some(method) => method.ty,
|
||||
None => self.tcx.expr_ty_adjusted(func_or_rcvr)
|
||||
None => self.tcx.tables().expr_ty_adjusted(func_or_rcvr)
|
||||
};
|
||||
|
||||
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
|
||||
|
|
|
|||
|
|
@ -1256,26 +1256,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
self.region_vars.new_bound(debruijn)
|
||||
}
|
||||
|
||||
/// Apply `adjustment` to the type of `expr`
|
||||
pub fn adjust_expr_ty(&self,
|
||||
expr: &hir::Expr,
|
||||
adjustment: Option<&adjustment::AutoAdjustment<'tcx>>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
let raw_ty = self.expr_ty(expr);
|
||||
let raw_ty = self.shallow_resolve(raw_ty);
|
||||
let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty);
|
||||
raw_ty.adjust(self.tcx,
|
||||
expr.span,
|
||||
expr.id,
|
||||
adjustment,
|
||||
|method_call| self.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.map(|method| resolve_ty(method.ty)))
|
||||
}
|
||||
|
||||
/// True if errors have been reported since this infcx was
|
||||
/// created. This is sometimes used as a heuristic to skip
|
||||
/// reporting errors that often occur as a result of earlier
|
||||
|
|
@ -1612,7 +1592,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
|
||||
let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id));
|
||||
let ty = self.tables.borrow().expr_ty_adjusted(expr);
|
||||
self.resolve_type_vars_or_error(&ty)
|
||||
}
|
||||
|
||||
|
|
@ -1656,9 +1636,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
.map(|method| method.def_id)
|
||||
}
|
||||
|
||||
pub fn adjustments(&self) -> Ref<NodeMap<adjustment::AutoAdjustment<'tcx>>> {
|
||||
pub fn adjustments(&self) -> Ref<NodeMap<adjustment::Adjustment<'tcx>>> {
|
||||
fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
|
||||
-> &'a NodeMap<adjustment::AutoAdjustment<'tcx>> {
|
||||
-> &'a NodeMap<adjustment::Adjustment<'tcx>> {
|
||||
&tables.adjustments
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
|
||||
match self.tcx.expr_ty_adjusted(lhs).sty {
|
||||
match self.tcx.tables().expr_ty_adjusted(lhs).sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
self.insert_def_id(def.struct_variant().field_named(name).did);
|
||||
}
|
||||
|
|
@ -137,7 +137,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) {
|
||||
match self.tcx.expr_ty_adjusted(lhs).sty {
|
||||
match self.tcx.tables().expr_ty_adjusted(lhs).sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
self.insert_def_id(def.struct_variant().fields[idx].did);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
hir::ExprCall(ref base, _) => {
|
||||
let base_type = self.tcx.expr_ty_adjusted(base);
|
||||
let base_type = self.tcx.tables().expr_ty_adjusted(base);
|
||||
debug!("effect: call case, base type is {:?}",
|
||||
base_type);
|
||||
if type_is_unsafe_function(base_type) {
|
||||
|
|
@ -176,7 +176,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
hir::ExprUnary(hir::UnDeref, ref base) => {
|
||||
let base_type = self.tcx.expr_ty_adjusted(base);
|
||||
let base_type = self.tcx.tables().expr_ty_adjusted(base);
|
||||
debug!("effect: unary case, base type is {:?}",
|
||||
base_type);
|
||||
if let ty::TyRawPtr(_) = base_type.sty {
|
||||
|
|
@ -200,7 +200,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
hir::ExprField(ref base_expr, field) => {
|
||||
if let ty::TyAdt(adt, ..) = self.tcx.expr_ty_adjusted(base_expr).sty {
|
||||
if let ty::TyAdt(adt, ..) = self.tcx.tables().expr_ty_adjusted(base_expr).sty {
|
||||
if adt.is_union() {
|
||||
self.require_unsafe(field.span, "access to union field");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -720,11 +720,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
//NOTE(@jroesch): mixed RefCell borrow causes crash
|
||||
let adj = infcx.adjustments().get(&expr.id).map(|x| x.clone());
|
||||
if let Some(adjustment) = adj {
|
||||
match adjustment {
|
||||
adjustment::AdjustNeverToAny(..) |
|
||||
adjustment::AdjustReifyFnPointer |
|
||||
adjustment::AdjustUnsafeFnPointer |
|
||||
adjustment::AdjustMutToConstPointer => {
|
||||
match adjustment.kind {
|
||||
adjustment::Adjust::NeverToAny |
|
||||
adjustment::Adjust::ReifyFnPointer |
|
||||
adjustment::Adjust::UnsafeFnPointer |
|
||||
adjustment::Adjust::MutToConstPointer => {
|
||||
// Creating a closure/fn-pointer or unsizing consumes
|
||||
// the input and stores it into the resulting rvalue.
|
||||
debug!("walk_adjustment: trivial adjustment");
|
||||
|
|
@ -732,8 +732,21 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
||||
}
|
||||
adjustment::AdjustDerefRef(ref adj) => {
|
||||
self.walk_autoderefref(expr, adj);
|
||||
adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => {
|
||||
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
|
||||
|
||||
self.walk_autoderefs(expr, autoderefs);
|
||||
|
||||
let cmt_derefd =
|
||||
return_if_err!(self.mc.cat_expr_autoderefd(expr, autoderefs));
|
||||
|
||||
let cmt_refd =
|
||||
self.walk_autoref(expr, cmt_derefd, autoref);
|
||||
|
||||
if unsize {
|
||||
// Unsizing consumes the thin pointer and produces a fat one.
|
||||
self.delegate_consume(expr.id, expr.span, cmt_refd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -770,28 +783,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn walk_autoderefref(&mut self,
|
||||
expr: &hir::Expr,
|
||||
adj: &adjustment::AutoDerefRef<'tcx>) {
|
||||
debug!("walk_autoderefref expr={:?} adj={:?}",
|
||||
expr,
|
||||
adj);
|
||||
|
||||
self.walk_autoderefs(expr, adj.autoderefs);
|
||||
|
||||
let cmt_derefd =
|
||||
return_if_err!(self.mc.cat_expr_autoderefd(expr, adj.autoderefs));
|
||||
|
||||
let cmt_refd =
|
||||
self.walk_autoref(expr, cmt_derefd, adj.autoref);
|
||||
|
||||
if adj.unsize.is_some() {
|
||||
// Unsizing consumes the thin pointer and produces a fat one.
|
||||
self.delegate_consume(expr.id, expr.span, cmt_refd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Walks the autoref `opt_autoref` applied to the autoderef'd
|
||||
/// `expr`. `cmt_derefd` is the mem-categorized form of `expr`
|
||||
/// after all relevant autoderefs have occurred. Because AutoRefs
|
||||
|
|
@ -803,7 +794,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
fn walk_autoref(&mut self,
|
||||
expr: &hir::Expr,
|
||||
cmt_base: mc::cmt<'tcx>,
|
||||
opt_autoref: Option<adjustment::AutoRef<'tcx>>)
|
||||
opt_autoref: Option<adjustment::AutoBorrow<'tcx>>)
|
||||
-> mc::cmt<'tcx>
|
||||
{
|
||||
debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
|
||||
|
|
@ -822,7 +813,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
};
|
||||
|
||||
match *autoref {
|
||||
adjustment::AutoPtr(r, m) => {
|
||||
adjustment::AutoBorrow::Ref(r, m) => {
|
||||
self.delegate.borrow(expr.id,
|
||||
expr.span,
|
||||
cmt_base,
|
||||
|
|
@ -831,7 +822,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
AutoRef);
|
||||
}
|
||||
|
||||
adjustment::AutoUnsafe(m) => {
|
||||
adjustment::AutoBorrow::RawPtr(m) => {
|
||||
debug!("walk_autoref: expr.id={} cmt_base={:?}",
|
||||
expr.id,
|
||||
cmt_base);
|
||||
|
|
|
|||
|
|
@ -1114,7 +1114,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
hir::ExprCall(ref f, ref args) => {
|
||||
// FIXME(canndrew): This is_never should really be an is_uninhabited
|
||||
let diverges = !self.ir.tcx.tables().is_method_call(expr.id) &&
|
||||
self.ir.tcx.expr_ty_adjusted(&f).fn_ret().0.is_never();
|
||||
self.ir.tcx.tables().expr_ty_adjusted(&f).fn_ret().0.is_never();
|
||||
let succ = if diverges {
|
||||
self.s.exit_ln
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -354,11 +354,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
|
||||
let unadjusted_ty = self.expr_ty(expr)?;
|
||||
Ok(unadjusted_ty.adjust(
|
||||
self.tcx(), expr.span, expr.id,
|
||||
self.infcx.adjustments().get(&expr.id),
|
||||
|method_call| self.infcx.node_method_ty(method_call)))
|
||||
self.infcx.expr_ty_adjusted(expr)
|
||||
}
|
||||
|
||||
fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
|
||||
|
|
@ -396,19 +392,21 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
Some(adjustment) => {
|
||||
match *adjustment {
|
||||
adjustment::AdjustDerefRef(
|
||||
adjustment::AutoDerefRef {
|
||||
autoref: None, unsize: None, autoderefs, ..}) => {
|
||||
match adjustment.kind {
|
||||
adjustment::Adjust::DerefRef {
|
||||
autoderefs,
|
||||
autoref: None,
|
||||
unsize: false
|
||||
} => {
|
||||
// Equivalent to *expr or something similar.
|
||||
self.cat_expr_autoderefd(expr, autoderefs)
|
||||
}
|
||||
|
||||
adjustment::AdjustNeverToAny(..) |
|
||||
adjustment::AdjustReifyFnPointer |
|
||||
adjustment::AdjustUnsafeFnPointer |
|
||||
adjustment::AdjustMutToConstPointer |
|
||||
adjustment::AdjustDerefRef(_) => {
|
||||
adjustment::Adjust::NeverToAny |
|
||||
adjustment::Adjust::ReifyFnPointer |
|
||||
adjustment::Adjust::UnsafeFnPointer |
|
||||
adjustment::Adjust::MutToConstPointer |
|
||||
adjustment::Adjust::DerefRef {..} => {
|
||||
debug!("cat_expr({:?}): {:?}",
|
||||
adjustment,
|
||||
expr);
|
||||
|
|
|
|||
|
|
@ -559,7 +559,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
|
|||
}
|
||||
hir::ExprField(ref base_e, ref field) => {
|
||||
span = field.span;
|
||||
match tcx.expr_ty_adjusted(base_e).sty {
|
||||
match tcx.tables().expr_ty_adjusted(base_e).sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
def.struct_variant().field_named(field.node).did
|
||||
}
|
||||
|
|
@ -569,7 +569,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
|
|||
}
|
||||
hir::ExprTupField(ref base_e, ref field) => {
|
||||
span = field.span;
|
||||
match tcx.expr_ty_adjusted(base_e).sty {
|
||||
match tcx.tables().expr_ty_adjusted(base_e).sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
def.struct_variant().fields[field.node].did
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub use self::AutoAdjustment::*;
|
||||
pub use self::AutoRef::*;
|
||||
|
||||
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFoldable};
|
||||
use ty::{self, Ty, TyCtxt, TypeAndMut};
|
||||
use ty::LvaluePreference::{NoPreference};
|
||||
|
||||
use syntax::ast;
|
||||
|
|
@ -20,116 +17,122 @@ use syntax_pos::Span;
|
|||
use hir;
|
||||
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum AutoAdjustment<'tcx> {
|
||||
AdjustNeverToAny(Ty<'tcx>), // go from ! to any type
|
||||
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
|
||||
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
|
||||
AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer
|
||||
AdjustDerefRef(AutoDerefRef<'tcx>),
|
||||
pub struct Adjustment<'tcx> {
|
||||
pub kind: Adjust<'tcx>,
|
||||
pub target: Ty<'tcx>
|
||||
}
|
||||
|
||||
/// 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:
|
||||
///
|
||||
/// ```
|
||||
/// AutoDerefRef {
|
||||
/// autoderefs: 1, // &[i32; 4] -> [i32; 4]
|
||||
/// autoref: Some(AutoPtr), // [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:
|
||||
///
|
||||
/// ```
|
||||
/// AutoDerefRef {
|
||||
/// autoderefs: 0,
|
||||
/// autoref: None,
|
||||
/// unsize: Some(Box<[i32]>),
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub struct AutoDerefRef<'tcx> {
|
||||
/// Step 1. Apply a number of dereferences, producing an lvalue.
|
||||
pub autoderefs: usize,
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum Adjust<'tcx> {
|
||||
/// Go from ! to any type.
|
||||
NeverToAny,
|
||||
|
||||
/// Step 2. Optionally produce a pointer/reference from the value.
|
||||
pub autoref: Option<AutoRef<'tcx>>,
|
||||
/// Go from a fn-item type to a fn-pointer type.
|
||||
ReifyFnPointer,
|
||||
|
||||
/// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
|
||||
/// `&[T]`. The stored type is the target pointer type. Note that
|
||||
/// the source could be a thin or fat pointer.
|
||||
pub unsize: Option<Ty<'tcx>>,
|
||||
/// Go from a safe fn pointer to an unsafe fn pointer.
|
||||
UnsafeFnPointer,
|
||||
|
||||
/// 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,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AutoAdjustment<'tcx> {
|
||||
impl<'tcx> Adjustment<'tcx> {
|
||||
pub fn is_identity(&self) -> bool {
|
||||
match *self {
|
||||
AdjustNeverToAny(ty) => ty.is_never(),
|
||||
AdjustReifyFnPointer |
|
||||
AdjustUnsafeFnPointer |
|
||||
AdjustMutToConstPointer => false,
|
||||
AdjustDerefRef(ref r) => r.is_identity(),
|
||||
match self.kind {
|
||||
Adjust::NeverToAny => self.target.is_never(),
|
||||
|
||||
Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true,
|
||||
|
||||
Adjust::ReifyFnPointer |
|
||||
Adjust::UnsafeFnPointer |
|
||||
Adjust::MutToConstPointer |
|
||||
Adjust::DerefRef {..} => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'tcx> AutoDerefRef<'tcx> {
|
||||
pub fn is_identity(&self) -> bool {
|
||||
self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum AutoRef<'tcx> {
|
||||
pub enum AutoBorrow<'tcx> {
|
||||
/// Convert from T to &T.
|
||||
AutoPtr(&'tcx ty::Region, hir::Mutability),
|
||||
Ref(&'tcx ty::Region, hir::Mutability),
|
||||
|
||||
/// Convert from T to *T.
|
||||
/// Value to thin pointer.
|
||||
AutoUnsafe(hir::Mutability),
|
||||
RawPtr(hir::Mutability),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
|
||||
|
|
@ -139,84 +142,6 @@ pub enum CustomCoerceUnsized {
|
|||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
|
||||
/// See `expr_ty_adjusted`
|
||||
pub fn adjust<F>(&'tcx self,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
expr_id: ast::NodeId,
|
||||
adjustment: Option<&AutoAdjustment<'tcx>>,
|
||||
mut method_type: F)
|
||||
-> Ty<'tcx> where
|
||||
F: FnMut(ty::MethodCall) -> Option<Ty<'tcx>>,
|
||||
{
|
||||
if let ty::TyError = self.sty {
|
||||
return self;
|
||||
}
|
||||
|
||||
return match adjustment {
|
||||
Some(adjustment) => {
|
||||
match *adjustment {
|
||||
AdjustNeverToAny(ref ty) => ty,
|
||||
|
||||
AdjustReifyFnPointer => {
|
||||
match self.sty {
|
||||
ty::TyFnDef(.., f) => tcx.mk_fn_ptr(f),
|
||||
_ => {
|
||||
bug!("AdjustReifyFnPointer adjustment on non-fn-item: {:?}",
|
||||
self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AdjustUnsafeFnPointer => {
|
||||
match self.sty {
|
||||
ty::TyFnPtr(b) => tcx.safe_to_unsafe_fn_ty(b),
|
||||
ref b => {
|
||||
bug!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: {:?}",
|
||||
b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AdjustMutToConstPointer => {
|
||||
match self.sty {
|
||||
ty::TyRawPtr(mt) => tcx.mk_ptr(ty::TypeAndMut {
|
||||
ty: mt.ty,
|
||||
mutbl: hir::MutImmutable
|
||||
}),
|
||||
ref b => {
|
||||
bug!("AdjustMutToConstPointer on non-raw-ptr: {:?}",
|
||||
b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AdjustDerefRef(ref adj) => {
|
||||
let mut adjusted_ty = self;
|
||||
|
||||
if !adjusted_ty.references_error() {
|
||||
for i in 0..adj.autoderefs {
|
||||
adjusted_ty =
|
||||
adjusted_ty.adjust_for_autoderef(tcx,
|
||||
expr_id,
|
||||
span,
|
||||
i as u32,
|
||||
&mut method_type);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(target) = adj.unsize {
|
||||
target
|
||||
} else {
|
||||
adjusted_ty.adjust_for_autoref(tcx, adj.autoref)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => self
|
||||
};
|
||||
}
|
||||
|
||||
pub fn adjust_for_autoderef<F>(&'tcx self,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
expr_id: ast::NodeId,
|
||||
|
|
@ -247,14 +172,14 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
|
|||
}
|
||||
|
||||
pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
autoref: Option<AutoRef<'tcx>>)
|
||||
autoref: Option<AutoBorrow<'tcx>>)
|
||||
-> Ty<'tcx> {
|
||||
match autoref {
|
||||
None => self,
|
||||
Some(AutoPtr(r, m)) => {
|
||||
Some(AutoBorrow::Ref(r, m)) => {
|
||||
tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m })
|
||||
}
|
||||
Some(AutoUnsafe(m)) => {
|
||||
Some(AutoBorrow::RawPtr(m)) => {
|
||||
tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ pub struct Tables<'tcx> {
|
|||
/// other items.
|
||||
pub item_substs: NodeMap<ty::ItemSubsts<'tcx>>,
|
||||
|
||||
pub adjustments: NodeMap<ty::adjustment::AutoAdjustment<'tcx>>,
|
||||
pub adjustments: NodeMap<ty::adjustment::Adjustment<'tcx>>,
|
||||
|
||||
pub method_map: ty::MethodMap<'tcx>,
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ impl<'a, 'gcx, 'tcx> Tables<'tcx> {
|
|||
// Returns the type of an expression as a monotype.
|
||||
//
|
||||
// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in
|
||||
// some cases, we insert `AutoAdjustment` annotations such as auto-deref or
|
||||
// some cases, we insert `Adjustment` annotations such as auto-deref or
|
||||
// auto-ref. The type returned by this function does not consider such
|
||||
// adjustments. See `expr_ty_adjusted()` instead.
|
||||
//
|
||||
|
|
@ -302,6 +302,17 @@ impl<'a, 'gcx, 'tcx> Tables<'tcx> {
|
|||
self.node_id_to_type_opt(expr.id)
|
||||
}
|
||||
|
||||
/// Returns the type of `expr`, considering any `Adjustment`
|
||||
/// entry recorded for that expression.
|
||||
pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> {
|
||||
self.adjustments.get(&expr.id)
|
||||
.map_or_else(|| self.expr_ty(expr), |adj| adj.target)
|
||||
}
|
||||
|
||||
pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option<Ty<'tcx>> {
|
||||
self.adjustments.get(&expr.id)
|
||||
.map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
|
||||
}
|
||||
|
||||
pub fn is_method_call(&self, expr_id: NodeId) -> bool {
|
||||
self.method_map.contains_key(&ty::MethodCall::expr(expr_id))
|
||||
|
|
|
|||
|
|
@ -176,8 +176,8 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
|
|||
r.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>)
|
||||
-> adjustment::AutoRef<'tcx> {
|
||||
fn fold_autoref(&mut self, ar: &adjustment::AutoBorrow<'tcx>)
|
||||
-> adjustment::AutoBorrow<'tcx> {
|
||||
ar.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2124,34 +2124,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
self.tables.borrow()
|
||||
}
|
||||
|
||||
/// Returns the type of `expr`, considering any `AutoAdjustment`
|
||||
/// entry recorded for that expression.
|
||||
///
|
||||
/// It would almost certainly be better to store the adjusted ty in with
|
||||
/// the `AutoAdjustment`, but I opted not to do this because it would
|
||||
/// require serializing and deserializing the type and, although that's not
|
||||
/// hard to do, I just hate that code so much I didn't want to touch it
|
||||
/// unless it was to fix it properly, which seemed a distraction from the
|
||||
/// thread at hand! -nmatsakis
|
||||
pub fn expr_ty_adjusted(self, expr: &hir::Expr) -> Ty<'gcx> {
|
||||
self.tables().expr_ty(expr)
|
||||
.adjust(self.global_tcx(), expr.span, expr.id,
|
||||
self.tables().adjustments.get(&expr.id),
|
||||
|method_call| {
|
||||
self.tables().method_map.get(&method_call).map(|method| method.ty)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn expr_ty_adjusted_opt(self, expr: &hir::Expr) -> Option<Ty<'gcx>> {
|
||||
self.tables().expr_ty_opt(expr).map(|t| t.adjust(self.global_tcx(),
|
||||
expr.span,
|
||||
expr.id,
|
||||
self.tables().adjustments.get(&expr.id),
|
||||
|method_call| {
|
||||
self.tables().method_map.get(&method_call).map(|method| method.ty)
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn expr_span(self, id: NodeId) -> Span {
|
||||
match self.map.find(id) {
|
||||
Some(ast_map::NodeExpr(e)) => {
|
||||
|
|
|
|||
|
|
@ -218,15 +218,15 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ItemSubsts<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoRef<'a> {
|
||||
type Lifted = ty::adjustment::AutoRef<'tcx>;
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> {
|
||||
type Lifted = ty::adjustment::AutoBorrow<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
match *self {
|
||||
ty::adjustment::AutoPtr(r, m) => {
|
||||
tcx.lift(&r).map(|r| ty::adjustment::AutoPtr(r, m))
|
||||
ty::adjustment::AutoBorrow::Ref(r, m) => {
|
||||
tcx.lift(&r).map(|r| ty::adjustment::AutoBorrow::Ref(r, m))
|
||||
}
|
||||
ty::adjustment::AutoUnsafe(m) => {
|
||||
Some(ty::adjustment::AutoUnsafe(m))
|
||||
ty::adjustment::AutoBorrow::RawPtr(m) => {
|
||||
Some(ty::adjustment::AutoBorrow::RawPtr(m))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -676,13 +676,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> {
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
ty::adjustment::AutoPtr(ref r, m) => {
|
||||
ty::adjustment::AutoPtr(r.fold_with(folder), m)
|
||||
ty::adjustment::AutoBorrow::Ref(ref r, m) => {
|
||||
ty::adjustment::AutoBorrow::Ref(r.fold_with(folder), m)
|
||||
}
|
||||
ty::adjustment::AutoUnsafe(m) => ty::adjustment::AutoUnsafe(m)
|
||||
ty::adjustment::AutoBorrow::RawPtr(m) => ty::adjustment::AutoBorrow::RawPtr(m)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -692,8 +692,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> {
|
|||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match *self {
|
||||
ty::adjustment::AutoPtr(r, _m) => r.visit_with(visitor),
|
||||
ty::adjustment::AutoUnsafe(_m) => false,
|
||||
ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor),
|
||||
ty::adjustment::AutoBorrow::RawPtr(_m) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -436,32 +436,9 @@ impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> {
|
||||
impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ty::adjustment::AdjustNeverToAny(ref target) => {
|
||||
write!(f, "AdjustNeverToAny({:?})", target)
|
||||
}
|
||||
ty::adjustment::AdjustReifyFnPointer => {
|
||||
write!(f, "AdjustReifyFnPointer")
|
||||
}
|
||||
ty::adjustment::AdjustUnsafeFnPointer => {
|
||||
write!(f, "AdjustUnsafeFnPointer")
|
||||
}
|
||||
ty::adjustment::AdjustMutToConstPointer => {
|
||||
write!(f, "AdjustMutToConstPointer")
|
||||
}
|
||||
ty::adjustment::AdjustDerefRef(ref data) => {
|
||||
write!(f, "{:?}", data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::adjustment::AutoDerefRef<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "AutoDerefRef({}, unsize={:?}, {:?})",
|
||||
self.autoderefs, self.unsize, self.autoref)
|
||||
write!(f, "{:?} -> {}", self.kind, self.target)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ use middle::stability;
|
|||
use rustc::cfg;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::adjustment;
|
||||
use rustc::traits::{self, Reveal};
|
||||
use rustc::hir::map as hir_map;
|
||||
use util::nodemap::NodeSet;
|
||||
|
|
@ -941,6 +940,8 @@ impl LateLintPass for UnconditionalRecursion {
|
|||
method: &ty::Method,
|
||||
id: ast::NodeId)
|
||||
-> bool {
|
||||
use rustc::ty::adjustment::*;
|
||||
|
||||
// Check for method calls and overloaded operators.
|
||||
let opt_m = tcx.tables().method_map.get(&ty::MethodCall::expr(id)).cloned();
|
||||
if let Some(m) = opt_m {
|
||||
|
|
@ -951,8 +952,8 @@ impl LateLintPass for UnconditionalRecursion {
|
|||
|
||||
// Check for overloaded autoderef method calls.
|
||||
let opt_adj = tcx.tables().adjustments.get(&id).cloned();
|
||||
if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj {
|
||||
for i in 0..adj.autoderefs {
|
||||
if let Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) = opt_adj {
|
||||
for i in 0..autoderefs {
|
||||
let method_call = ty::MethodCall::autoderef(id, i as u32);
|
||||
if let Some(m) = tcx.tables().method_map.get(&method_call)
|
||||
.cloned() {
|
||||
|
|
|
|||
|
|
@ -442,15 +442,14 @@ impl LateLintPass for UnusedAllocation {
|
|||
}
|
||||
|
||||
if let Some(adjustment) = cx.tcx.tables().adjustments.get(&e.id) {
|
||||
if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { ref autoref, .. }) =
|
||||
*adjustment {
|
||||
if let adjustment::Adjust::DerefRef { autoref, .. } = adjustment.kind {
|
||||
match autoref {
|
||||
&Some(adjustment::AutoPtr(_, hir::MutImmutable)) => {
|
||||
Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => {
|
||||
cx.span_lint(UNUSED_ALLOCATION,
|
||||
e.span,
|
||||
"unnecessary allocation, use & instead");
|
||||
}
|
||||
&Some(adjustment::AutoPtr(_, hir::MutMutable)) => {
|
||||
Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => {
|
||||
cx.span_lint(UNUSED_ALLOCATION,
|
||||
e.span,
|
||||
"unnecessary allocation, use &mut instead");
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ enum TableEntry<'tcx> {
|
|||
Def(Def),
|
||||
NodeType(Ty<'tcx>),
|
||||
ItemSubsts(ty::ItemSubsts<'tcx>),
|
||||
Adjustment(ty::adjustment::AutoAdjustment<'tcx>),
|
||||
Adjustment(ty::adjustment::Adjustment<'tcx>),
|
||||
ConstQualif(ConstQualif),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
|
|||
ast_expr: &'tcx hir::Expr)
|
||||
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
|
||||
let tcx = hir.tcx();
|
||||
let ty = tcx.expr_ty_adjusted(ast_expr);
|
||||
let ty = tcx.tables().expr_ty_adjusted(ast_expr);
|
||||
let span = tcx.map.span(item_id);
|
||||
let mut builder = Builder::new(hir, span, 0, ty);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,15 +35,15 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
|
||||
|
||||
let mut expr = make_mirror_unadjusted(cx, self);
|
||||
let adj = cx.tcx.tables().adjustments.get(&self.id).cloned();
|
||||
|
||||
debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
|
||||
expr, cx.tcx.tables().adjustments.get(&self.id));
|
||||
expr, adj);
|
||||
|
||||
// Now apply adjustments, if any.
|
||||
match cx.tcx.tables().adjustments.get(&self.id) {
|
||||
match adj.map(|adj| (adj.kind, adj.target)) {
|
||||
None => {}
|
||||
Some(&ty::adjustment::AdjustReifyFnPointer) => {
|
||||
let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
|
||||
Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
ty: adjusted_ty,
|
||||
|
|
@ -51,8 +51,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||
kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
Some(&ty::adjustment::AdjustUnsafeFnPointer) => {
|
||||
let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
|
||||
Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
ty: adjusted_ty,
|
||||
|
|
@ -60,7 +59,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||
kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
Some(&ty::adjustment::AdjustNeverToAny(adjusted_ty)) => {
|
||||
Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
ty: adjusted_ty,
|
||||
|
|
@ -68,8 +67,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||
kind: ExprKind::NeverToAny { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
Some(&ty::adjustment::AdjustMutToConstPointer) => {
|
||||
let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
|
||||
Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
ty: adjusted_ty,
|
||||
|
|
@ -77,8 +75,9 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||
kind: ExprKind::Cast { source: expr.to_ref() },
|
||||
};
|
||||
}
|
||||
Some(&ty::adjustment::AdjustDerefRef(ref adj)) => {
|
||||
for i in 0..adj.autoderefs {
|
||||
Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize },
|
||||
adjusted_ty)) => {
|
||||
for i in 0..autoderefs {
|
||||
let i = i as u32;
|
||||
let adjusted_ty =
|
||||
expr.ty.adjust_for_autoderef(
|
||||
|
|
@ -128,10 +127,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||
};
|
||||
}
|
||||
|
||||
if let Some(autoref) = adj.autoref {
|
||||
if let Some(autoref) = autoref {
|
||||
let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
|
||||
match autoref {
|
||||
ty::adjustment::AutoPtr(r, m) => {
|
||||
ty::adjustment::AutoBorrow::Ref(r, m) => {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
ty: adjusted_ty,
|
||||
|
|
@ -143,7 +142,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||
},
|
||||
};
|
||||
}
|
||||
ty::adjustment::AutoUnsafe(m) => {
|
||||
ty::adjustment::AutoBorrow::RawPtr(m) => {
|
||||
// Convert this to a suitable `&foo` and
|
||||
// then an unsafe coercion. Limit the region to be just this
|
||||
// expression.
|
||||
|
|
@ -169,10 +168,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(target) = adj.unsize {
|
||||
if unsize {
|
||||
expr = Expr {
|
||||
temp_lifetime: temp_lifetime,
|
||||
ty: target,
|
||||
ty: adjusted_ty,
|
||||
span: self.span,
|
||||
kind: ExprKind::Unsize { source: expr.to_ref() },
|
||||
};
|
||||
|
|
@ -578,7 +577,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
ExprKind::Loop { condition: None,
|
||||
body: block::to_expr_ref(cx, body) },
|
||||
hir::ExprField(ref source, name) => {
|
||||
let index = match cx.tcx.expr_ty_adjusted(source).sty {
|
||||
let index = match cx.tcx.tables().expr_ty_adjusted(source).sty {
|
||||
ty::TyAdt(adt_def, _) =>
|
||||
adt_def.variants[0].index_of_field_named(name.node),
|
||||
ref ty =>
|
||||
|
|
@ -893,7 +892,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
argrefs.extend(
|
||||
args.iter()
|
||||
.map(|arg| {
|
||||
let arg_ty = cx.tcx.expr_ty_adjusted(arg);
|
||||
let arg_ty = cx.tcx.tables().expr_ty_adjusted(arg);
|
||||
let adjusted_ty =
|
||||
cx.tcx.mk_ref(region,
|
||||
ty::TypeAndMut { ty: arg_ty,
|
||||
|
|
|
|||
|
|
@ -625,14 +625,16 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
|
|||
|
||||
/// Check the adjustments of an expression
|
||||
fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
|
||||
match v.tcx.tables().adjustments.get(&e.id) {
|
||||
None |
|
||||
Some(&ty::adjustment::AdjustNeverToAny(..)) |
|
||||
Some(&ty::adjustment::AdjustReifyFnPointer) |
|
||||
Some(&ty::adjustment::AdjustUnsafeFnPointer) |
|
||||
Some(&ty::adjustment::AdjustMutToConstPointer) => {}
|
||||
use rustc::ty::adjustment::*;
|
||||
|
||||
Some(&ty::adjustment::AdjustDerefRef(ty::adjustment::AutoDerefRef { autoderefs, .. })) => {
|
||||
match v.tcx.tables().adjustments.get(&e.id).map(|adj| adj.kind) {
|
||||
None |
|
||||
Some(Adjust::NeverToAny) |
|
||||
Some(Adjust::ReifyFnPointer) |
|
||||
Some(Adjust::UnsafeFnPointer) |
|
||||
Some(Adjust::MutToConstPointer) => {}
|
||||
|
||||
Some(Adjust::DerefRef { autoderefs, .. }) => {
|
||||
if (0..autoderefs as u32)
|
||||
.any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
|
|
|
|||
|
|
@ -1380,7 +1380,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
|
|||
return;
|
||||
}
|
||||
};
|
||||
let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty;
|
||||
let ty = &self.tcx.tables().expr_ty_adjusted(&hir_node).sty;
|
||||
match *ty {
|
||||
ty::TyAdt(def, _) => {
|
||||
let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
|
||||
pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
|
||||
let hir_node = self.tcx.map.expect_expr(expr.id);
|
||||
let ty = self.tcx.expr_ty_adjusted_opt(&hir_node);
|
||||
let ty = self.tcx.tables().expr_ty_adjusted_opt(&hir_node);
|
||||
if ty.is_none() || ty.unwrap().sty == ty::TyError {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -432,7 +432,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
return None;
|
||||
}
|
||||
};
|
||||
match self.tcx.expr_ty_adjusted(&hir_node).sty {
|
||||
match self.tcx.tables().expr_ty_adjusted(&hir_node).sty {
|
||||
ty::TyAdt(def, _) if !def.is_enum() => {
|
||||
let f = def.struct_variant().field_named(ident.node.name);
|
||||
let sub_span = self.span_utils.span_for_last_ident(expr.span);
|
||||
|
|
@ -451,7 +451,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
}
|
||||
}
|
||||
ast::ExprKind::Struct(ref path, ..) => {
|
||||
match self.tcx.expr_ty_adjusted(&hir_node).sty {
|
||||
match self.tcx.tables().expr_ty_adjusted(&hir_node).sty {
|
||||
ty::TyAdt(def, _) if !def.is_enum() => {
|
||||
let sub_span = self.span_utils.span_for_last_ident(path.span);
|
||||
filter!(self.span_utils, sub_span, path.span, None);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// If the callee is a bare function or a closure, then we're all set.
|
||||
match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty {
|
||||
ty::TyFnDef(..) | ty::TyFnPtr(_) => {
|
||||
self.write_autoderef_adjustment(callee_expr.id, autoderefs);
|
||||
self.write_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty);
|
||||
return Some(CallStep::Builtin);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,10 +65,7 @@ use check::FnCtxt;
|
|||
use rustc::hir;
|
||||
use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
|
||||
use rustc::traits::{self, ObligationCause};
|
||||
use rustc::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
|
||||
use rustc::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
|
||||
use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
|
||||
use rustc::ty::adjustment::AdjustNeverToAny;
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||
use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::error::TypeError;
|
||||
|
|
@ -93,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, AutoAdjustment<'tcx>)>;
|
||||
type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, Adjust<'tcx>)>;
|
||||
|
||||
fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
|
||||
to_mutbl: hir::Mutability)
|
||||
|
|
@ -144,12 +141,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
|
||||
/// Synthesize an identity adjustment.
|
||||
fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||
Ok((ty,
|
||||
AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: 0,
|
||||
autoref: None,
|
||||
unsize: None,
|
||||
})))
|
||||
Ok((ty, Adjust::DerefRef {
|
||||
autoderefs: 0,
|
||||
autoref: None,
|
||||
unsize: false,
|
||||
}))
|
||||
}
|
||||
|
||||
fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx>
|
||||
|
|
@ -166,7 +162,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
if a.is_never() {
|
||||
return Ok((b, AdjustNeverToAny(b)));
|
||||
return Ok((b, Adjust::NeverToAny));
|
||||
}
|
||||
|
||||
// Consider coercing the subtype to a DST
|
||||
|
|
@ -396,17 +392,16 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
ty::TyRef(r_borrow, _) => r_borrow,
|
||||
_ => span_bug!(span, "expected a ref type, got {:?}", ty),
|
||||
};
|
||||
let autoref = Some(AutoPtr(r_borrow, mt_b.mutbl));
|
||||
let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl));
|
||||
debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}",
|
||||
ty,
|
||||
autoderefs,
|
||||
autoref);
|
||||
Ok((ty,
|
||||
AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: autoref,
|
||||
unsize: None,
|
||||
})))
|
||||
Ok((ty, Adjust::DerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: autoref,
|
||||
unsize: false,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -437,11 +432,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
|
||||
let coercion = Coercion(self.origin.span());
|
||||
let r_borrow = self.next_region_var(coercion);
|
||||
(mt_a.ty, Some(AutoPtr(r_borrow, mt_b.mutbl)))
|
||||
(mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)))
|
||||
}
|
||||
(&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
|
||||
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
||||
(mt_a.ty, Some(AutoUnsafe(mt_b.mutbl)))
|
||||
(mt_a.ty, Some(AutoBorrow::RawPtr(mt_b.mutbl)))
|
||||
}
|
||||
_ => (source, None),
|
||||
};
|
||||
|
|
@ -497,13 +492,13 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
|
||||
*self.unsizing_obligations.borrow_mut() = leftover_predicates;
|
||||
|
||||
let adjustment = AutoDerefRef {
|
||||
let adjustment = Adjust::DerefRef {
|
||||
autoderefs: if reborrow.is_some() { 1 } else { 0 },
|
||||
autoref: reborrow,
|
||||
unsize: Some(target),
|
||||
unsize: true,
|
||||
};
|
||||
debug!("Success, coerced with {:?}", adjustment);
|
||||
Ok((target, AdjustDerefRef(adjustment)))
|
||||
Ok((target, adjustment))
|
||||
}
|
||||
|
||||
fn coerce_from_safe_fn(&self,
|
||||
|
|
@ -516,7 +511,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
(hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
|
||||
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
|
||||
return self.unify_and_identity(unsafe_a, b)
|
||||
.map(|(ty, _)| (ty, AdjustUnsafeFnPointer));
|
||||
.map(|(ty, _)| (ty, Adjust::UnsafeFnPointer));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -555,7 +550,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
ty::TyFnPtr(_) => {
|
||||
let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
|
||||
self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b)
|
||||
.map(|(ty, _)| (ty, AdjustReifyFnPointer))
|
||||
.map(|(ty, _)| (ty, Adjust::ReifyFnPointer))
|
||||
}
|
||||
_ => self.unify_and_identity(a, b),
|
||||
}
|
||||
|
|
@ -585,17 +580,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
|
||||
|
||||
// Although references and unsafe ptrs have the same
|
||||
// representation, we still register an AutoDerefRef so that
|
||||
// representation, we still register an Adjust::DerefRef so that
|
||||
// regionck knows that the region for `a` must be valid here.
|
||||
Ok((ty,
|
||||
if is_ref {
|
||||
AdjustDerefRef(AutoDerefRef {
|
||||
Adjust::DerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(AutoUnsafe(mutbl_b)),
|
||||
unsize: None,
|
||||
})
|
||||
autoref: Some(AutoBorrow::RawPtr(mutbl_b)),
|
||||
unsize: false,
|
||||
}
|
||||
} else if mt_a.mutbl != mutbl_b {
|
||||
AdjustMutToConstPointer
|
||||
Adjust::MutToConstPointer
|
||||
} else {
|
||||
noop
|
||||
}))
|
||||
|
|
@ -606,24 +601,25 @@ fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>,
|
|||
exprs: &E,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> CoerceResult<'tcx>
|
||||
-> RelateResult<'tcx, Adjustment<'tcx>>
|
||||
where E: Fn() -> I,
|
||||
I: IntoIterator<Item = &'b hir::Expr>
|
||||
{
|
||||
|
||||
let (ty, adjustment) = indent(|| coerce.coerce(exprs, a, b))?;
|
||||
let (ty, adjust) = indent(|| coerce.coerce(exprs, a, b))?;
|
||||
|
||||
let fcx = coerce.fcx;
|
||||
if let AdjustDerefRef(auto) = adjustment {
|
||||
if auto.unsize.is_some() {
|
||||
let mut obligations = coerce.unsizing_obligations.borrow_mut();
|
||||
for obligation in obligations.drain(..) {
|
||||
fcx.register_predicate(obligation);
|
||||
}
|
||||
if let Adjust::DerefRef { unsize: true, .. } = adjust {
|
||||
let mut obligations = coerce.unsizing_obligations.borrow_mut();
|
||||
for obligation in obligations.drain(..) {
|
||||
fcx.register_predicate(obligation);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((ty, adjustment))
|
||||
Ok(Adjustment {
|
||||
kind: adjust,
|
||||
target: ty
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
|
@ -641,17 +637,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
|
||||
self.commit_if_ok(|_| {
|
||||
let (ty, adjustment) = apply(&mut coerce, &|| Some(expr), source, target)?;
|
||||
let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?;
|
||||
if !adjustment.is_identity() {
|
||||
debug!("Success, coerced with {:?}", adjustment);
|
||||
match self.tables.borrow().adjustments.get(&expr.id) {
|
||||
None |
|
||||
Some(&AdjustNeverToAny(..)) => (),
|
||||
Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => (),
|
||||
_ => bug!("expr already has an adjustment on it!"),
|
||||
};
|
||||
self.write_adjustment(expr.id, adjustment);
|
||||
}
|
||||
Ok(ty)
|
||||
Ok(adjustment.target)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -705,12 +701,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
// Reify both sides and return the reified fn pointer type.
|
||||
let fn_ptr = self.tcx.mk_fn_ptr(fty);
|
||||
for expr in exprs().into_iter().chain(Some(new)) {
|
||||
// No adjustments can produce a fn item, so this should never trip.
|
||||
assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
|
||||
self.write_adjustment(expr.id, AdjustReifyFnPointer);
|
||||
self.write_adjustment(expr.id, Adjustment {
|
||||
kind: Adjust::ReifyFnPointer,
|
||||
target: fn_ptr
|
||||
});
|
||||
}
|
||||
return Ok(self.tcx.mk_fn_ptr(fty));
|
||||
return Ok(fn_ptr);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -724,11 +724,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
if !self.tables.borrow().adjustments.contains_key(&new.id) {
|
||||
let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty));
|
||||
match result {
|
||||
Ok((ty, adjustment)) => {
|
||||
Ok(adjustment) => {
|
||||
if !adjustment.is_identity() {
|
||||
self.write_adjustment(new.id, adjustment);
|
||||
}
|
||||
return Ok(ty);
|
||||
return Ok(adjustment.target);
|
||||
}
|
||||
Err(e) => first_error = Some(e),
|
||||
}
|
||||
|
|
@ -738,10 +738,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// This requires ensuring there are no coercions applied to *any* of the
|
||||
// previous expressions, other than noop reborrows (ignoring lifetimes).
|
||||
for expr in exprs() {
|
||||
let noop = match self.tables.borrow().adjustments.get(&expr.id) {
|
||||
Some(&AdjustDerefRef(AutoDerefRef { autoderefs: 1,
|
||||
autoref: Some(AutoPtr(_, mutbl_adj)),
|
||||
unsize: None })) => {
|
||||
let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| adj.kind) {
|
||||
Some(Adjust::DerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(AutoBorrow::Ref(_, mutbl_adj)),
|
||||
unsize: false
|
||||
}) => {
|
||||
match self.node_ty(expr.id).sty {
|
||||
ty::TyRef(_, mt_orig) => {
|
||||
// Reborrow that we can safely ignore.
|
||||
|
|
@ -750,7 +752,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
Some(&AdjustNeverToAny(_)) => true,
|
||||
Some(Adjust::NeverToAny) => true,
|
||||
Some(_) => false,
|
||||
None => true,
|
||||
};
|
||||
|
|
@ -783,18 +785,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
})
|
||||
}
|
||||
}
|
||||
Ok((ty, adjustment)) => {
|
||||
Ok(adjustment) => {
|
||||
if !adjustment.is_identity() {
|
||||
let mut tables = self.tables.borrow_mut();
|
||||
for expr in exprs() {
|
||||
let previous = self.tables.borrow().adjustments.get(&expr.id).cloned();
|
||||
if let Some(AdjustNeverToAny(_)) = previous {
|
||||
self.write_adjustment(expr.id, AdjustNeverToAny(ty));
|
||||
} else {
|
||||
self.write_adjustment(expr.id, adjustment);
|
||||
if let Some(&mut Adjustment {
|
||||
kind: Adjust::NeverToAny,
|
||||
ref mut target
|
||||
}) = tables.adjustments.get_mut(&expr.id) {
|
||||
*target = adjustment.target;
|
||||
continue;
|
||||
}
|
||||
tables.adjustments.insert(expr.id, adjustment);
|
||||
}
|
||||
}
|
||||
Ok(ty)
|
||||
Ok(adjustment.target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use hir::def_id::DefId;
|
|||
use rustc::ty::subst::Substs;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
|
||||
use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::infer::{self, InferOk, TypeOrigin};
|
||||
use syntax_pos::Span;
|
||||
|
|
@ -140,20 +140,19 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
|||
unadjusted_self_ty: Ty<'tcx>,
|
||||
pick: &probe::Pick<'tcx>)
|
||||
-> Ty<'tcx> {
|
||||
let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
|
||||
let autoref = if let Some(mutbl) = pick.autoref {
|
||||
let region = self.next_region_var(infer::Autoref(self.span));
|
||||
let autoref = AutoPtr(region, mutbl);
|
||||
(Some(autoref),
|
||||
pick.unsize.map(|target| target.adjust_for_autoref(self.tcx, Some(autoref))))
|
||||
Some(AutoBorrow::Ref(region, mutbl))
|
||||
} else {
|
||||
// No unsizing should be performed without autoref (at
|
||||
// least during method dispach). This is because we
|
||||
// currently only unsize `[T;N]` to `[T]`, and naturally
|
||||
// that must occur being a reference.
|
||||
assert!(pick.unsize.is_none());
|
||||
(None, None)
|
||||
None
|
||||
};
|
||||
|
||||
|
||||
// Commit the autoderefs by calling `autoderef` again, but this
|
||||
// time writing the results into the various tables.
|
||||
let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
|
||||
|
|
@ -163,19 +162,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
|||
autoderef.unambiguous_final_ty();
|
||||
autoderef.finalize(LvaluePreference::NoPreference, Some(self.self_expr));
|
||||
|
||||
// Write out the final adjustment.
|
||||
self.write_adjustment(self.self_expr.id,
|
||||
AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: pick.autoderefs,
|
||||
autoref: autoref,
|
||||
unsize: unsize,
|
||||
}));
|
||||
let target = pick.unsize.unwrap_or(autoderefd_ty);
|
||||
let target = target.adjust_for_autoref(self.tcx, autoref);
|
||||
|
||||
if let Some(target) = unsize {
|
||||
target
|
||||
} else {
|
||||
autoderefd_ty.adjust_for_autoref(self.tcx, autoref)
|
||||
}
|
||||
// Write out the final adjustment.
|
||||
self.write_adjustment(self.self_expr.id, Adjustment {
|
||||
kind: Adjust::DerefRef {
|
||||
autoderefs: pick.autoderefs,
|
||||
autoref: autoref,
|
||||
unsize: pick.unsize.is_some(),
|
||||
},
|
||||
target: target
|
||||
});
|
||||
|
||||
target
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -463,29 +463,23 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
|||
|
||||
// Fix up autoderefs and derefs.
|
||||
for (i, &expr) in exprs.iter().rev().enumerate() {
|
||||
debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr);
|
||||
|
||||
// Count autoderefs.
|
||||
let autoderef_count = match self.tables
|
||||
.borrow()
|
||||
.adjustments
|
||||
.get(&expr.id) {
|
||||
Some(&AdjustDerefRef(ref adj)) => adj.autoderefs,
|
||||
Some(_) | None => 0,
|
||||
};
|
||||
|
||||
debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?} \
|
||||
autoderef_count={}",
|
||||
i,
|
||||
expr,
|
||||
autoderef_count);
|
||||
|
||||
if autoderef_count > 0 {
|
||||
let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
|
||||
autoderef.nth(autoderef_count).unwrap_or_else(|| {
|
||||
span_bug!(expr.span,
|
||||
"expr was deref-able {} times but now isn't?",
|
||||
autoderef_count);
|
||||
});
|
||||
autoderef.finalize(PreferMutLvalue, Some(expr));
|
||||
let adjustment = self.tables.borrow().adjustments.get(&expr.id).cloned();
|
||||
match adjustment {
|
||||
Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => {
|
||||
if autoderefs > 0 {
|
||||
let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
|
||||
autoderef.nth(autoderefs).unwrap_or_else(|| {
|
||||
span_bug!(expr.span,
|
||||
"expr was deref-able {} times but now isn't?",
|
||||
autoderefs);
|
||||
});
|
||||
autoderef.finalize(PreferMutLvalue, Some(expr));
|
||||
}
|
||||
}
|
||||
Some(_) | None => {}
|
||||
}
|
||||
|
||||
// Don't retry the first one or we might infinite loop!
|
||||
|
|
@ -503,45 +497,55 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
|||
// ought to recode this routine so it doesn't
|
||||
// (ab)use the normal type checking paths.
|
||||
let adj = self.tables.borrow().adjustments.get(&base_expr.id).cloned();
|
||||
let (autoderefs, unsize) = match adj {
|
||||
Some(AdjustDerefRef(adr)) => {
|
||||
match adr.autoref {
|
||||
let (autoderefs, unsize, adjusted_base_ty) = match adj {
|
||||
Some(Adjustment {
|
||||
kind: Adjust::DerefRef { autoderefs, autoref, unsize },
|
||||
target
|
||||
}) => {
|
||||
match autoref {
|
||||
None => {
|
||||
assert!(adr.unsize.is_none());
|
||||
(adr.autoderefs, None)
|
||||
}
|
||||
Some(AutoPtr(..)) => {
|
||||
(adr.autoderefs,
|
||||
adr.unsize.map(|target| {
|
||||
target.builtin_deref(false, NoPreference)
|
||||
.expect("fixup: AutoPtr is not &T")
|
||||
.ty
|
||||
}))
|
||||
assert!(!unsize);
|
||||
}
|
||||
Some(AutoBorrow::Ref(..)) => {}
|
||||
Some(_) => {
|
||||
span_bug!(base_expr.span,
|
||||
"unexpected adjustment autoref {:?}",
|
||||
adr);
|
||||
adj);
|
||||
}
|
||||
}
|
||||
|
||||
(autoderefs, unsize, if unsize {
|
||||
target.builtin_deref(false, NoPreference)
|
||||
.expect("fixup: AutoBorrow::Ref is not &T")
|
||||
.ty
|
||||
} else {
|
||||
let ty = self.node_ty(base_expr.id);
|
||||
let mut ty = self.shallow_resolve(ty);
|
||||
let mut method_type = |method_call: ty::MethodCall| {
|
||||
self.tables.borrow().method_map.get(&method_call).map(|m| {
|
||||
self.resolve_type_vars_if_possible(&m.ty)
|
||||
})
|
||||
};
|
||||
|
||||
if !ty.references_error() {
|
||||
for i in 0..autoderefs {
|
||||
ty = ty.adjust_for_autoderef(self.tcx,
|
||||
base_expr.id,
|
||||
base_expr.span,
|
||||
i as u32,
|
||||
&mut method_type);
|
||||
}
|
||||
}
|
||||
|
||||
ty
|
||||
})
|
||||
}
|
||||
None => (0, None),
|
||||
None => (0, false, self.node_ty(base_expr.id)),
|
||||
Some(_) => {
|
||||
span_bug!(base_expr.span, "unexpected adjustment type");
|
||||
}
|
||||
};
|
||||
|
||||
let (adjusted_base_ty, unsize) = if let Some(target) = unsize {
|
||||
(target, true)
|
||||
} else {
|
||||
(self.adjust_expr_ty(base_expr,
|
||||
Some(&AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: None,
|
||||
unsize: None,
|
||||
}))),
|
||||
false)
|
||||
};
|
||||
let index_expr_ty = self.node_ty(index_expr.id);
|
||||
|
||||
let result = self.try_index_step(ty::MethodCall::expr(expr.id),
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use hir::def_id::DefId;
|
|||
use rustc::ty::subst::Substs;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
|
||||
use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||
use rustc::infer;
|
||||
|
||||
use syntax::ast;
|
||||
|
|
@ -294,11 +294,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
unsize,
|
||||
method_ty.explicit_self);
|
||||
|
||||
match method_ty.explicit_self {
|
||||
let autoref = match method_ty.explicit_self {
|
||||
ty::ExplicitSelfCategory::ByValue => {
|
||||
// Trait method is fn(self), no transformation needed.
|
||||
assert!(!unsize);
|
||||
self.write_autoderef_adjustment(self_expr.id, autoderefs);
|
||||
None
|
||||
}
|
||||
|
||||
ty::ExplicitSelfCategory::ByReference(..) => {
|
||||
|
|
@ -306,16 +306,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// autoref. Pull the region etc out of the type of first argument.
|
||||
match transformed_self_ty.sty {
|
||||
ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => {
|
||||
self.write_adjustment(self_expr.id,
|
||||
AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: Some(AutoPtr(region, mutbl)),
|
||||
unsize: if unsize {
|
||||
Some(transformed_self_ty)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}));
|
||||
Some(AutoBorrow::Ref(region, mutbl))
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
|
@ -331,7 +322,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
"unexpected explicit self type in operator method: {:?}",
|
||||
method_ty.explicit_self);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.write_adjustment(self_expr.id, Adjustment {
|
||||
kind: Adjust::DerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: autoref,
|
||||
unsize: unsize
|
||||
},
|
||||
target: transformed_self_ty
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1564,20 +1564,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
pub fn write_autoderef_adjustment(&self,
|
||||
node_id: ast::NodeId,
|
||||
derefs: usize) {
|
||||
self.write_adjustment(
|
||||
node_id,
|
||||
adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
|
||||
derefs: usize,
|
||||
adjusted_ty: Ty<'tcx>) {
|
||||
self.write_adjustment(node_id, adjustment::Adjustment {
|
||||
kind: adjustment::Adjust::DerefRef {
|
||||
autoderefs: derefs,
|
||||
autoref: None,
|
||||
unsize: None
|
||||
})
|
||||
);
|
||||
unsize: false
|
||||
},
|
||||
target: adjusted_ty
|
||||
});
|
||||
}
|
||||
|
||||
pub fn write_adjustment(&self,
|
||||
node_id: ast::NodeId,
|
||||
adj: adjustment::AutoAdjustment<'tcx>) {
|
||||
adj: adjustment::Adjustment<'tcx>) {
|
||||
debug!("write_adjustment(node_id={}, adj={:?})", node_id, adj);
|
||||
|
||||
if adj.is_identity() {
|
||||
|
|
@ -1743,21 +1744,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
t
|
||||
}
|
||||
|
||||
/// Apply `adjustment` to the type of `expr`
|
||||
pub fn adjust_expr_ty(&self,
|
||||
expr: &hir::Expr,
|
||||
adjustment: Option<&adjustment::AutoAdjustment<'tcx>>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
let raw_ty = self.node_ty(expr.id);
|
||||
let raw_ty = self.shallow_resolve(raw_ty);
|
||||
let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty);
|
||||
raw_ty.adjust(self.tcx, expr.span, expr.id, adjustment, |method_call| {
|
||||
self.tables.borrow().method_map.get(&method_call)
|
||||
.map(|method| resolve_ty(method.ty))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
|
||||
match self.tables.borrow().node_types.get(&id) {
|
||||
Some(&t) => t,
|
||||
|
|
@ -2294,7 +2280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
debug!("try_index_step: success, using built-in indexing");
|
||||
// If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
|
||||
assert!(!unsize);
|
||||
self.write_autoderef_adjustment(base_expr.id, autoderefs);
|
||||
self.write_autoderef_adjustment(base_expr.id, autoderefs, adjusted_ty);
|
||||
return Some((tcx.types.usize, ty));
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -2850,9 +2836,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
// In case we did perform an adjustment, we have to update
|
||||
// the type of the block, because old trans still uses it.
|
||||
let adj = self.tables.borrow().adjustments.get(&then.id).cloned();
|
||||
if res.is_ok() && adj.is_some() {
|
||||
self.write_ty(then_blk.id, self.adjust_expr_ty(then, adj.as_ref()));
|
||||
if res.is_ok() {
|
||||
let adj = self.tables.borrow().adjustments.get(&then.id).cloned();
|
||||
if let Some(adj) = adj {
|
||||
self.write_ty(then_blk.id, adj.target);
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
|
|
@ -2913,7 +2901,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
let field_ty = self.field_ty(expr.span, field, substs);
|
||||
if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
|
||||
autoderef.finalize(lvalue_pref, Some(base));
|
||||
self.write_autoderef_adjustment(base.id, autoderefs);
|
||||
self.write_autoderef_adjustment(base.id, autoderefs, base_t);
|
||||
return field_ty;
|
||||
}
|
||||
private_candidate = Some((base_def.did, field_ty));
|
||||
|
|
@ -3031,7 +3019,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
if let Some(field_ty) = field {
|
||||
autoderef.finalize(lvalue_pref, Some(base));
|
||||
self.write_autoderef_adjustment(base.id, autoderefs);
|
||||
self.write_autoderef_adjustment(base.id, autoderefs, base_t);
|
||||
return field_ty;
|
||||
}
|
||||
}
|
||||
|
|
@ -3341,8 +3329,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
if ty.is_never() {
|
||||
if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(expr.id) {
|
||||
let adj_ty = self.next_diverging_ty_var();
|
||||
let adj = adjustment::AdjustNeverToAny(adj_ty);
|
||||
self.write_adjustment(expr.id, adj);
|
||||
self.write_adjustment(expr.id, adjustment::Adjustment {
|
||||
kind: adjustment::Adjust::NeverToAny,
|
||||
target: adj_ty
|
||||
});
|
||||
return adj_ty;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,23 +259,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
|||
self.resolve_type(t)
|
||||
}
|
||||
|
||||
fn resolve_method_type(&self, method_call: MethodCall) -> Option<Ty<'tcx>> {
|
||||
let method_ty = self.tables.borrow().method_map
|
||||
.get(&method_call).map(|method| method.ty);
|
||||
method_ty.map(|method_ty| self.resolve_type(method_ty))
|
||||
}
|
||||
|
||||
/// Try to resolve the type for the given node.
|
||||
pub fn resolve_expr_type_adjusted(&mut self, expr: &hir::Expr) -> Ty<'tcx> {
|
||||
let ty_unadjusted = self.resolve_node_type(expr.id);
|
||||
if ty_unadjusted.references_error() {
|
||||
ty_unadjusted
|
||||
} else {
|
||||
ty_unadjusted.adjust(
|
||||
self.tcx, expr.span, expr.id,
|
||||
self.tables.borrow().adjustments.get(&expr.id),
|
||||
|method_call| self.resolve_method_type(method_call))
|
||||
}
|
||||
let ty = self.tables.borrow().expr_ty_adjusted(expr);
|
||||
self.resolve_type(ty)
|
||||
}
|
||||
|
||||
fn visit_fn_body(&mut self,
|
||||
|
|
@ -558,10 +545,8 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
|
|||
let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
|
||||
if let Some(adjustment) = adjustment {
|
||||
debug!("adjustment={:?}", adjustment);
|
||||
match adjustment {
|
||||
adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
|
||||
autoderefs, ref autoref, ..
|
||||
}) => {
|
||||
match adjustment.kind {
|
||||
adjustment::Adjust::DerefRef { autoderefs, ref autoref, .. } => {
|
||||
let expr_ty = self.resolve_node_type(expr.id);
|
||||
self.constrain_autoderefs(expr, autoderefs, expr_ty);
|
||||
if let Some(ref autoref) = *autoref {
|
||||
|
|
@ -951,7 +936,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
|||
let origin = infer::ParameterOrigin::OverloadedDeref;
|
||||
self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr);
|
||||
|
||||
// Treat overloaded autoderefs as if an AutoRef adjustment
|
||||
// Treat overloaded autoderefs as if an AutoBorrow adjustment
|
||||
// was applied on the base type, as that is always the case.
|
||||
let fn_sig = method.ty.fn_sig();
|
||||
let fn_sig = // late-bound regions should have been instantiated
|
||||
|
|
@ -1065,15 +1050,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
|||
id: ast::NodeId,
|
||||
minimum_lifetime: &'tcx ty::Region)
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
|
||||
// Try to resolve the type. If we encounter an error, then typeck
|
||||
// is going to fail anyway, so just stop here and let typeck
|
||||
// report errors later on in the writeback phase.
|
||||
let ty0 = self.resolve_node_type(id);
|
||||
let ty = ty0.adjust(tcx, origin.span(), id,
|
||||
self.tables.borrow().adjustments.get(&id),
|
||||
|method_call| self.resolve_method_type(method_call));
|
||||
let ty = self.tables.borrow().adjustments.get(&id).map_or(ty0, |adj| adj.target);
|
||||
let ty = self.resolve_type(ty);
|
||||
debug!("constrain_regions_in_type_of_node(\
|
||||
ty={}, ty0={}, id={}, minimum_lifetime={:?})",
|
||||
ty, ty0,
|
||||
|
|
@ -1170,7 +1152,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
|||
fn link_autoref(&self,
|
||||
expr: &hir::Expr,
|
||||
autoderefs: usize,
|
||||
autoref: &adjustment::AutoRef<'tcx>)
|
||||
autoref: &adjustment::AutoBorrow<'tcx>)
|
||||
{
|
||||
debug!("link_autoref(autoref={:?})", autoref);
|
||||
let mc = mc::MemCategorizationContext::new(self);
|
||||
|
|
@ -1178,12 +1160,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
|||
debug!("expr_cmt={:?}", expr_cmt);
|
||||
|
||||
match *autoref {
|
||||
adjustment::AutoPtr(r, m) => {
|
||||
adjustment::AutoBorrow::Ref(r, m) => {
|
||||
self.link_region(expr.span, r,
|
||||
ty::BorrowKind::from_mutbl(m), expr_cmt);
|
||||
}
|
||||
|
||||
adjustment::AutoUnsafe(m) => {
|
||||
adjustment::AutoBorrow::RawPtr(m) => {
|
||||
let r = self.tcx.node_scope_region(expr.id);
|
||||
self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -381,36 +381,40 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
Some(adjustment) => {
|
||||
let resolved_adjustment = match adjustment {
|
||||
adjustment::AdjustNeverToAny(ty) => {
|
||||
adjustment::AdjustNeverToAny(self.resolve(&ty, reason))
|
||||
let resolved_adjustment = match adjustment.kind {
|
||||
adjustment::Adjust::NeverToAny => {
|
||||
adjustment::Adjust::NeverToAny
|
||||
}
|
||||
|
||||
adjustment::AdjustReifyFnPointer => {
|
||||
adjustment::AdjustReifyFnPointer
|
||||
adjustment::Adjust::ReifyFnPointer => {
|
||||
adjustment::Adjust::ReifyFnPointer
|
||||
}
|
||||
|
||||
adjustment::AdjustMutToConstPointer => {
|
||||
adjustment::AdjustMutToConstPointer
|
||||
adjustment::Adjust::MutToConstPointer => {
|
||||
adjustment::Adjust::MutToConstPointer
|
||||
}
|
||||
|
||||
adjustment::AdjustUnsafeFnPointer => {
|
||||
adjustment::AdjustUnsafeFnPointer
|
||||
adjustment::Adjust::UnsafeFnPointer => {
|
||||
adjustment::Adjust::UnsafeFnPointer
|
||||
}
|
||||
|
||||
adjustment::AdjustDerefRef(adj) => {
|
||||
for autoderef in 0..adj.autoderefs {
|
||||
adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => {
|
||||
for autoderef in 0..autoderefs {
|
||||
let method_call = MethodCall::autoderef(id, autoderef as u32);
|
||||
self.visit_method_map_entry(reason, method_call);
|
||||
}
|
||||
|
||||
adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
|
||||
autoderefs: adj.autoderefs,
|
||||
autoref: self.resolve(&adj.autoref, reason),
|
||||
unsize: self.resolve(&adj.unsize, reason),
|
||||
})
|
||||
adjustment::Adjust::DerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: self.resolve(&autoref, reason),
|
||||
unsize: unsize,
|
||||
}
|
||||
}
|
||||
};
|
||||
let resolved_adjustment = adjustment::Adjustment {
|
||||
kind: resolved_adjustment,
|
||||
target: self.resolve(&adjustment.target, reason)
|
||||
};
|
||||
debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
|
||||
self.tcx().tables.borrow_mut().adjustments.insert(
|
||||
id, resolved_adjustment);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue