rustc: record the target type of every adjustment.

This commit is contained in:
Eduard Burtescu 2016-10-20 06:33:20 +03:00
parent 6a8d131e5d
commit 0d7201ef46
29 changed files with 421 additions and 581 deletions

View file

@ -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);

View file

@ -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
}

View file

@ -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);
}

View file

@ -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");
}

View file

@ -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);

View file

@ -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 {

View file

@ -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);

View file

@ -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
}

View file

@ -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 })
}
}

View file

@ -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))

View file

@ -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)
}
}

View file

@ -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)) => {

View file

@ -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,
}
}
}

View file

@ -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)
}
}

View file

@ -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() {

View file

@ -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");

View file

@ -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),
}

View file

@ -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);

View file

@ -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,

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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)
}
}
}

View file

@ -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),

View file

@ -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
});
}
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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);