mirror of https://github.com/rust-lang/rust.git
rustc: decompose Adjustment into a vector of adjustment steps.
This commit is contained in:
parent
91d603a2a7
commit
194fe695e3
|
@ -99,16 +99,20 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::Ad
|
||||||
ty::adjustment::Adjust::ReifyFnPointer |
|
ty::adjustment::Adjust::ReifyFnPointer |
|
||||||
ty::adjustment::Adjust::UnsafeFnPointer |
|
ty::adjustment::Adjust::UnsafeFnPointer |
|
||||||
ty::adjustment::Adjust::ClosureFnPointer |
|
ty::adjustment::Adjust::ClosureFnPointer |
|
||||||
ty::adjustment::Adjust::MutToConstPointer => {}
|
ty::adjustment::Adjust::MutToConstPointer |
|
||||||
ty::adjustment::Adjust::Deref(ref autoderefs) => {
|
ty::adjustment::Adjust::Unsize => {}
|
||||||
autoderefs.hash_stable(hcx, hasher);
|
ty::adjustment::Adjust::Deref(ref overloaded) => {
|
||||||
|
overloaded.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
ty::adjustment::Adjust::Borrow(ref autoref) => {
|
||||||
|
autoref.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, autoref, unsize, target });
|
impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
|
||||||
impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl, target });
|
impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl });
|
||||||
impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
|
impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
|
||||||
impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
|
impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
|
||||||
|
|
||||||
|
|
|
@ -704,89 +704,55 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
// consumed or borrowed as part of the automatic adjustment
|
// consumed or borrowed as part of the automatic adjustment
|
||||||
// process.
|
// process.
|
||||||
fn walk_adjustment(&mut self, expr: &hir::Expr) {
|
fn walk_adjustment(&mut self, expr: &hir::Expr) {
|
||||||
let infcx = self.mc.infcx;
|
|
||||||
//NOTE(@jroesch): mixed RefCell borrow causes crash
|
//NOTE(@jroesch): mixed RefCell borrow causes crash
|
||||||
let adj = infcx.tables.borrow().adjustments.get(&expr.id).cloned();
|
let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec();
|
||||||
let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||||
if let Some(adjustment) = adj {
|
for adjustment in adjustments {
|
||||||
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
|
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
|
||||||
match adjustment.kind {
|
match adjustment.kind {
|
||||||
adjustment::Adjust::NeverToAny |
|
adjustment::Adjust::NeverToAny |
|
||||||
adjustment::Adjust::ReifyFnPointer |
|
adjustment::Adjust::ReifyFnPointer |
|
||||||
adjustment::Adjust::UnsafeFnPointer |
|
adjustment::Adjust::UnsafeFnPointer |
|
||||||
adjustment::Adjust::ClosureFnPointer |
|
adjustment::Adjust::ClosureFnPointer |
|
||||||
adjustment::Adjust::MutToConstPointer => {
|
adjustment::Adjust::MutToConstPointer |
|
||||||
|
adjustment::Adjust::Unsize => {
|
||||||
// Creating a closure/fn-pointer or unsizing consumes
|
// Creating a closure/fn-pointer or unsizing consumes
|
||||||
// the input and stores it into the resulting rvalue.
|
// the input and stores it into the resulting rvalue.
|
||||||
self.delegate_consume(expr.id, expr.span, cmt);
|
self.delegate_consume(expr.id, expr.span, cmt.clone());
|
||||||
assert!(adjustment.autoref.is_none() && !adjustment.unsize);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
adjustment::Adjust::Deref(ref autoderefs) => {
|
|
||||||
cmt = return_if_err!(self.walk_autoderefs(expr, cmt, autoderefs));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmt = self.walk_autoref(expr, cmt, adjustment.autoref);
|
adjustment::Adjust::Deref(None) => {}
|
||||||
|
|
||||||
if adjustment.unsize {
|
// Autoderefs for overloaded Deref calls in fact reference
|
||||||
// Unsizing consumes the thin pointer and produces a fat one.
|
// their receiver. That is, if we have `(*x)` where `x`
|
||||||
self.delegate_consume(expr.id, expr.span, cmt);
|
// is of type `Rc<T>`, then this in fact is equivalent to
|
||||||
}
|
// `x.deref()`. Since `deref()` is declared with `&self`,
|
||||||
}
|
// this is an autoref of `x`.
|
||||||
}
|
adjustment::Adjust::Deref(Some(ref deref)) => {
|
||||||
|
|
||||||
/// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have
|
|
||||||
/// `(*x)` where `x` is of type `Rc<T>`, then this in fact is equivalent to `x.deref()`. Since
|
|
||||||
/// `deref()` is declared with `&self`, this is an autoref of `x`.
|
|
||||||
fn walk_autoderefs(&mut self,
|
|
||||||
expr: &hir::Expr,
|
|
||||||
mut cmt: mc::cmt<'tcx>,
|
|
||||||
autoderefs: &[Option<adjustment::OverloadedDeref<'tcx>>])
|
|
||||||
-> mc::McResult<mc::cmt<'tcx>> {
|
|
||||||
debug!("walk_autoderefs expr={:?} autoderefs={:?}", expr, autoderefs);
|
|
||||||
|
|
||||||
for &overloaded in autoderefs {
|
|
||||||
if let Some(deref) = overloaded {
|
|
||||||
let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
|
let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
|
||||||
self.delegate.borrow(expr.id, expr.span, cmt.clone(),
|
self.delegate.borrow(expr.id, expr.span, cmt.clone(),
|
||||||
deref.region, bk, AutoRef);
|
deref.region, bk, AutoRef);
|
||||||
cmt = self.mc.cat_overloaded_autoderef(expr, deref)?;
|
|
||||||
} else {
|
|
||||||
cmt = self.mc.cat_deref(expr, cmt, false)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(cmt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walks the autoref `opt_autoref` applied to the autoderef'd
|
adjustment::Adjust::Borrow(ref autoref) => {
|
||||||
/// `expr`. `cmt_derefd` is the mem-categorized form of `expr`
|
self.walk_autoref(expr, cmt.clone(), autoref);
|
||||||
/// after all relevant autoderefs have occurred. Because AutoRefs
|
}
|
||||||
/// can be recursive, this function is recursive: it first walks
|
}
|
||||||
/// deeply all the way down the autoref chain, and then processes
|
cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment));
|
||||||
/// the autorefs on the way out. At each point, it returns the
|
}
|
||||||
/// `cmt` for the rvalue that will be produced by introduced an
|
}
|
||||||
/// autoref.
|
|
||||||
|
/// Walks the autoref `autoref` applied to the autoderef'd
|
||||||
|
/// `expr`. `cmt_base` is the mem-categorized form of `expr`
|
||||||
|
/// after all relevant autoderefs have occurred.
|
||||||
fn walk_autoref(&mut self,
|
fn walk_autoref(&mut self,
|
||||||
expr: &hir::Expr,
|
expr: &hir::Expr,
|
||||||
cmt_base: mc::cmt<'tcx>,
|
cmt_base: mc::cmt<'tcx>,
|
||||||
opt_autoref: Option<adjustment::AutoBorrow<'tcx>>)
|
autoref: &adjustment::AutoBorrow<'tcx>) {
|
||||||
-> mc::cmt<'tcx>
|
debug!("walk_autoref(expr.id={} cmt_base={:?} autoref={:?})",
|
||||||
{
|
|
||||||
debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
|
|
||||||
expr.id,
|
expr.id,
|
||||||
cmt_base,
|
cmt_base,
|
||||||
opt_autoref);
|
autoref);
|
||||||
|
|
||||||
let cmt_base_ty = cmt_base.ty;
|
|
||||||
|
|
||||||
let autoref = match opt_autoref {
|
|
||||||
Some(ref autoref) => autoref,
|
|
||||||
None => {
|
|
||||||
// No AutoRef.
|
|
||||||
return cmt_base;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match *autoref {
|
match *autoref {
|
||||||
adjustment::AutoBorrow::Ref(r, m) => {
|
adjustment::AutoBorrow::Ref(r, m) => {
|
||||||
|
@ -816,14 +782,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
AutoUnsafe);
|
AutoUnsafe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the categorization for the result of the autoref.
|
|
||||||
// This is always an rvalue, since we are producing a new
|
|
||||||
// (temporary) indirection.
|
|
||||||
|
|
||||||
let adj_ty = cmt_base_ty.adjust_for_autoref(self.tcx(), opt_autoref);
|
|
||||||
|
|
||||||
self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -466,29 +466,51 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
|
pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
|
||||||
match self.infcx.tables.borrow().adjustments.get(&expr.id) {
|
// This recursion helper avoids going through *too many*
|
||||||
None => {
|
// adjustments, since *only* non-overloaded deref recurses.
|
||||||
// No adjustments.
|
fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>,
|
||||||
self.cat_expr_unadjusted(expr)
|
expr: &hir::Expr,
|
||||||
|
adjustments: &[adjustment::Adjustment<'tcx>])
|
||||||
|
-> McResult<cmt<'tcx>> {
|
||||||
|
match adjustments.split_last() {
|
||||||
|
None => mc.cat_expr_unadjusted(expr),
|
||||||
|
Some((adjustment, previous)) => {
|
||||||
|
mc.cat_expr_adjusted_with(expr, || helper(mc, expr, previous), adjustment)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(adjustment) => {
|
helper(self, expr, self.infcx.tables.borrow().expr_adjustments(expr))
|
||||||
debug!("cat_expr({:?}): {:?}", adjustment, expr);
|
}
|
||||||
|
|
||||||
|
pub fn cat_expr_adjusted(&self, expr: &hir::Expr,
|
||||||
|
previous: cmt<'tcx>,
|
||||||
|
adjustment: &adjustment::Adjustment<'tcx>)
|
||||||
|
-> McResult<cmt<'tcx>> {
|
||||||
|
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cat_expr_adjusted_with<F>(&self, expr: &hir::Expr,
|
||||||
|
previous: F,
|
||||||
|
adjustment: &adjustment::Adjustment<'tcx>)
|
||||||
|
-> McResult<cmt<'tcx>>
|
||||||
|
where F: FnOnce() -> McResult<cmt<'tcx>>
|
||||||
|
{
|
||||||
|
debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
|
||||||
|
let target = self.infcx.resolve_type_vars_if_possible(&adjustment.target);
|
||||||
match adjustment.kind {
|
match adjustment.kind {
|
||||||
adjustment::Adjust::Deref(ref autoderefs)
|
adjustment::Adjust::Deref(overloaded) => {
|
||||||
if adjustment.autoref.is_none() && !adjustment.unsize => {
|
|
||||||
// Equivalent to *expr or something similar.
|
// Equivalent to *expr or something similar.
|
||||||
let mut cmt = self.cat_expr_unadjusted(expr)?;
|
let base = if let Some(deref) = overloaded {
|
||||||
debug!("cat_expr: autoderefs={:?}, cmt={:?}",
|
let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut {
|
||||||
autoderefs, cmt);
|
ty: target,
|
||||||
for &overloaded in autoderefs {
|
mutbl: deref.mutbl,
|
||||||
if let Some(deref) = overloaded {
|
});
|
||||||
cmt = self.cat_overloaded_autoderef(expr, deref)?;
|
self.cat_rvalue_node(expr.id, expr.span, ref_ty)
|
||||||
} else {
|
} else {
|
||||||
cmt = self.cat_deref(expr, cmt, false)?;
|
previous()?
|
||||||
}
|
};
|
||||||
}
|
self.cat_deref(expr, base, false)
|
||||||
return Ok(cmt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
adjustment::Adjust::NeverToAny |
|
adjustment::Adjust::NeverToAny |
|
||||||
|
@ -496,12 +518,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
adjustment::Adjust::UnsafeFnPointer |
|
adjustment::Adjust::UnsafeFnPointer |
|
||||||
adjustment::Adjust::ClosureFnPointer |
|
adjustment::Adjust::ClosureFnPointer |
|
||||||
adjustment::Adjust::MutToConstPointer |
|
adjustment::Adjust::MutToConstPointer |
|
||||||
adjustment::Adjust::Deref(_) => {
|
adjustment::Adjust::Borrow(_) |
|
||||||
|
adjustment::Adjust::Unsize => {
|
||||||
// Result is an rvalue.
|
// Result is an rvalue.
|
||||||
let expr_ty = self.expr_ty_adjusted(expr)?;
|
Ok(self.cat_rvalue_node(expr.id, expr.span, target))
|
||||||
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -931,21 +951,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
self.cat_deref(expr, base_cmt, implicit)
|
self.cat_deref(expr, base_cmt, implicit)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cat_overloaded_autoderef(&self,
|
|
||||||
expr: &hir::Expr,
|
|
||||||
deref: adjustment::OverloadedDeref<'tcx>)
|
|
||||||
-> McResult<cmt<'tcx>> {
|
|
||||||
debug!("cat_overloaded_autoderef: deref={:?}", deref);
|
|
||||||
|
|
||||||
let target = self.infcx.resolve_type_vars_if_possible(&deref.target);
|
|
||||||
let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut {
|
|
||||||
ty: target,
|
|
||||||
mutbl: deref.mutbl,
|
|
||||||
});
|
|
||||||
let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty);
|
|
||||||
self.cat_deref(expr, base_cmt, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cat_deref<N:ast_node>(&self,
|
pub fn cat_deref<N:ast_node>(&self,
|
||||||
node: &N,
|
node: &N,
|
||||||
base_cmt: cmt<'tcx>,
|
base_cmt: cmt<'tcx>,
|
||||||
|
|
|
@ -10,29 +10,18 @@
|
||||||
|
|
||||||
use hir;
|
use hir;
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use ty::{self, Ty, TyCtxt, TypeAndMut};
|
use ty::{self, Ty, TyCtxt};
|
||||||
use ty::subst::Substs;
|
use ty::subst::Substs;
|
||||||
|
|
||||||
|
|
||||||
/// Represents coercing a value to a different type of value.
|
/// Represents coercing a value to a different type of value.
|
||||||
///
|
///
|
||||||
/// We transform values by following the following steps in order:
|
/// We transform values by following a number of `Adjust` steps in order.
|
||||||
/// 1. Apply a step of `Adjust` (see its variants for details).
|
/// See the documentation on variants of `Adjust` for more details.
|
||||||
/// 2. If `autoref` is `Some(_)`, then take the address and produce either a
|
|
||||||
/// `&` or `*` pointer.
|
|
||||||
/// 3. If `unsize` is `true`, 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:
|
/// Here are some common scenarios:
|
||||||
///
|
///
|
||||||
/// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
|
/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
|
||||||
/// Here the pointer will be dereferenced N times (where a dereference can
|
/// Here the pointer will be dereferenced N times (where a dereference can
|
||||||
/// happen to raw or borrowed pointers or any smart pointer which implements
|
/// happen to raw or borrowed pointers or any smart pointer which implements
|
||||||
/// Deref, including Box<_>). The types of dereferences is given by
|
/// Deref, including Box<_>). The types of dereferences is given by
|
||||||
|
@ -48,12 +37,9 @@ use ty::subst::Substs;
|
||||||
/// represented by:
|
/// represented by:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// Adjustment {
|
/// Deref(None) -> [i32; 4],
|
||||||
/// kind: Adjust::Deref(vec![None]),// &[i32; 4] -> [i32; 4]
|
/// Borrow(AutoBorrow::Ref) -> &[i32; 4],
|
||||||
/// autoref: Some(AutoBorrow::Ref), // [i32; 4] -> &[i32; 4]
|
/// Unsize -> &[i32],
|
||||||
/// unsize: true, // &[i32; 4] -> &[i32]
|
|
||||||
/// target: `[i32]`,
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
|
/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
|
||||||
|
@ -67,28 +53,10 @@ use ty::subst::Substs;
|
||||||
/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
|
/// 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
|
/// 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]> ->
|
/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
|
||||||
/// Box<[i32]> is represented by:
|
/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// Adjustment {
|
|
||||||
/// kind: Adjust::Deref(vec![]),
|
|
||||||
/// autoref: None,
|
|
||||||
/// unsize: true,
|
|
||||||
/// target: `Box<[i32]>`,
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||||
pub struct Adjustment<'tcx> {
|
pub struct Adjustment<'tcx> {
|
||||||
/// Step 1.
|
|
||||||
pub kind: Adjust<'tcx>,
|
pub kind: Adjust<'tcx>,
|
||||||
|
|
||||||
/// Step 2. Optionally produce a pointer/reference from the value.
|
|
||||||
pub 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.
|
|
||||||
pub unsize: bool,
|
|
||||||
|
|
||||||
pub target: Ty<'tcx>,
|
pub target: Ty<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,27 +77,23 @@ pub enum Adjust<'tcx> {
|
||||||
/// Go from a mut raw pointer to a const raw pointer.
|
/// Go from a mut raw pointer to a const raw pointer.
|
||||||
MutToConstPointer,
|
MutToConstPointer,
|
||||||
|
|
||||||
/// Apply a number of dereferences, producing an lvalue,
|
/// Dereference once, producing an lvalue.
|
||||||
/// if there are more than 0 dereferences.
|
Deref(Option<OverloadedDeref<'tcx>>),
|
||||||
Deref(Vec<Option<OverloadedDeref<'tcx>>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Adjustment<'tcx> {
|
/// Take the address and produce either a `&` or `*` pointer.
|
||||||
pub fn is_identity(&self) -> bool {
|
Borrow(AutoBorrow<'tcx>),
|
||||||
if self.autoref.is_some() || self.unsize {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
match self.kind {
|
|
||||||
Adjust::NeverToAny => self.target.is_never(),
|
|
||||||
|
|
||||||
Adjust::Deref(ref autoderefs) => autoderefs.is_empty(),
|
/// Unsize a pointer/reference value, e.g. `&[T; n]` to
|
||||||
|
/// `&[T]`. Note that the source could be a thin or fat pointer.
|
||||||
Adjust::ReifyFnPointer |
|
/// This will do things like convert thin pointers to fat
|
||||||
Adjust::UnsafeFnPointer |
|
/// pointers, or convert structs containing thin pointers to
|
||||||
Adjust::ClosureFnPointer |
|
/// structs containing fat pointers, or convert between fat
|
||||||
Adjust::MutToConstPointer => false,
|
/// 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.
|
||||||
|
Unsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
|
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
|
||||||
|
@ -140,7 +104,6 @@ impl<'tcx> Adjustment<'tcx> {
|
||||||
pub struct OverloadedDeref<'tcx> {
|
pub struct OverloadedDeref<'tcx> {
|
||||||
pub region: ty::Region<'tcx>,
|
pub region: ty::Region<'tcx>,
|
||||||
pub mutbl: hir::Mutability,
|
pub mutbl: hir::Mutability,
|
||||||
pub target: Ty<'tcx>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> {
|
impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> {
|
||||||
|
@ -185,19 +148,3 @@ pub enum CustomCoerceUnsized {
|
||||||
/// Records the index of the field being coerced.
|
/// Records the index of the field being coerced.
|
||||||
Struct(usize)
|
Struct(usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
|
|
||||||
pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|
||||||
autoref: Option<AutoBorrow<'tcx>>)
|
|
||||||
-> Ty<'tcx> {
|
|
||||||
match autoref {
|
|
||||||
None => self,
|
|
||||||
Some(AutoBorrow::Ref(r, m)) => {
|
|
||||||
tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m })
|
|
||||||
}
|
|
||||||
Some(AutoBorrow::RawPtr(m)) => {
|
|
||||||
tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -221,7 +221,7 @@ pub struct TypeckTables<'tcx> {
|
||||||
/// other items.
|
/// other items.
|
||||||
pub node_substs: NodeMap<&'tcx Substs<'tcx>>,
|
pub node_substs: NodeMap<&'tcx Substs<'tcx>>,
|
||||||
|
|
||||||
pub adjustments: NodeMap<ty::adjustment::Adjustment<'tcx>>,
|
pub adjustments: NodeMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
|
||||||
|
|
||||||
/// Borrows
|
/// Borrows
|
||||||
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
|
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
|
||||||
|
@ -343,16 +343,24 @@ impl<'tcx> TypeckTables<'tcx> {
|
||||||
self.node_id_to_type_opt(expr.id)
|
self.node_id_to_type_opt(expr.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr_adjustments(&self, expr: &hir::Expr)
|
||||||
|
-> &[ty::adjustment::Adjustment<'tcx>] {
|
||||||
|
self.adjustments.get(&expr.id).map_or(&[], |a| &a[..])
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the type of `expr`, considering any `Adjustment`
|
/// Returns the type of `expr`, considering any `Adjustment`
|
||||||
/// entry recorded for that expression.
|
/// entry recorded for that expression.
|
||||||
pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> {
|
pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> {
|
||||||
self.adjustments.get(&expr.id)
|
self.expr_adjustments(expr)
|
||||||
|
.last()
|
||||||
.map_or_else(|| self.expr_ty(expr), |adj| adj.target)
|
.map_or_else(|| self.expr_ty(expr), |adj| adj.target)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option<Ty<'tcx>> {
|
pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option<Ty<'tcx>> {
|
||||||
self.adjustments.get(&expr.id)
|
self.expr_adjustments(expr)
|
||||||
.map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
|
.last()
|
||||||
|
.map(|adj| adj.target)
|
||||||
|
.or_else(|| self.expr_ty_opt(expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_method_call(&self, expr: &hir::Expr) -> bool {
|
pub fn is_method_call(&self, expr: &hir::Expr) -> bool {
|
||||||
|
|
|
@ -224,13 +224,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> {
|
||||||
type Lifted = ty::adjustment::Adjustment<'tcx>;
|
type Lifted = ty::adjustment::Adjustment<'tcx>;
|
||||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||||
tcx.lift(&self.kind).and_then(|kind| {
|
tcx.lift(&self.kind).and_then(|kind| {
|
||||||
tcx.lift(&(self.autoref, self.target)).map(|(autoref, target)| {
|
tcx.lift(&self.target).map(|target| {
|
||||||
ty::adjustment::Adjustment {
|
ty::adjustment::Adjustment { kind, target }
|
||||||
kind,
|
|
||||||
autoref,
|
|
||||||
unsize: self.unsize,
|
|
||||||
target,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -250,8 +245,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
|
||||||
Some(ty::adjustment::Adjust::ClosureFnPointer),
|
Some(ty::adjustment::Adjust::ClosureFnPointer),
|
||||||
ty::adjustment::Adjust::MutToConstPointer =>
|
ty::adjustment::Adjust::MutToConstPointer =>
|
||||||
Some(ty::adjustment::Adjust::MutToConstPointer),
|
Some(ty::adjustment::Adjust::MutToConstPointer),
|
||||||
ty::adjustment::Adjust::Deref(ref autoderefs) => {
|
ty::adjustment::Adjust::Unsize =>
|
||||||
tcx.lift(autoderefs).map(ty::adjustment::Adjust::Deref)
|
Some(ty::adjustment::Adjust::Unsize),
|
||||||
|
ty::adjustment::Adjust::Deref(ref overloaded) => {
|
||||||
|
tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref)
|
||||||
|
}
|
||||||
|
ty::adjustment::Adjust::Borrow(ref autoref) => {
|
||||||
|
tcx.lift(autoref).map(ty::adjustment::Adjust::Borrow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,11 +260,10 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
|
||||||
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
|
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
|
||||||
type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
|
type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
|
||||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||||
tcx.lift(&(self.region, self.target)).map(|(region, target)| {
|
tcx.lift(&self.region).map(|region| {
|
||||||
ty::adjustment::OverloadedDeref {
|
ty::adjustment::OverloadedDeref {
|
||||||
region,
|
region,
|
||||||
mutbl: self.mutbl,
|
mutbl: self.mutbl,
|
||||||
target,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -685,15 +684,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjustment<'tcx> {
|
||||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||||
ty::adjustment::Adjustment {
|
ty::adjustment::Adjustment {
|
||||||
kind: self.kind.fold_with(folder),
|
kind: self.kind.fold_with(folder),
|
||||||
autoref: self.autoref.fold_with(folder),
|
|
||||||
unsize: self.unsize,
|
|
||||||
target: self.target.fold_with(folder),
|
target: self.target.fold_with(folder),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||||
self.kind.visit_with(visitor) ||
|
self.kind.visit_with(visitor) ||
|
||||||
self.autoref.visit_with(visitor) ||
|
|
||||||
self.target.visit_with(visitor)
|
self.target.visit_with(visitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -705,9 +701,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> {
|
||||||
ty::adjustment::Adjust::ReifyFnPointer |
|
ty::adjustment::Adjust::ReifyFnPointer |
|
||||||
ty::adjustment::Adjust::UnsafeFnPointer |
|
ty::adjustment::Adjust::UnsafeFnPointer |
|
||||||
ty::adjustment::Adjust::ClosureFnPointer |
|
ty::adjustment::Adjust::ClosureFnPointer |
|
||||||
ty::adjustment::Adjust::MutToConstPointer => self.clone(),
|
ty::adjustment::Adjust::MutToConstPointer |
|
||||||
ty::adjustment::Adjust::Deref(ref autoderefs) => {
|
ty::adjustment::Adjust::Unsize => self.clone(),
|
||||||
ty::adjustment::Adjust::Deref(autoderefs.fold_with(folder))
|
ty::adjustment::Adjust::Deref(ref overloaded) => {
|
||||||
|
ty::adjustment::Adjust::Deref(overloaded.fold_with(folder))
|
||||||
|
}
|
||||||
|
ty::adjustment::Adjust::Borrow(ref autoref) => {
|
||||||
|
ty::adjustment::Adjust::Borrow(autoref.fold_with(folder))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -718,9 +718,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> {
|
||||||
ty::adjustment::Adjust::ReifyFnPointer |
|
ty::adjustment::Adjust::ReifyFnPointer |
|
||||||
ty::adjustment::Adjust::UnsafeFnPointer |
|
ty::adjustment::Adjust::UnsafeFnPointer |
|
||||||
ty::adjustment::Adjust::ClosureFnPointer |
|
ty::adjustment::Adjust::ClosureFnPointer |
|
||||||
ty::adjustment::Adjust::MutToConstPointer => false,
|
ty::adjustment::Adjust::MutToConstPointer |
|
||||||
ty::adjustment::Adjust::Deref(ref autoderefs) => {
|
ty::adjustment::Adjust::Unsize => false,
|
||||||
autoderefs.visit_with(visitor)
|
ty::adjustment::Adjust::Deref(ref overloaded) => {
|
||||||
|
overloaded.visit_with(visitor)
|
||||||
|
}
|
||||||
|
ty::adjustment::Adjust::Borrow(ref autoref) => {
|
||||||
|
autoref.visit_with(visitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -731,12 +735,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> {
|
||||||
ty::adjustment::OverloadedDeref {
|
ty::adjustment::OverloadedDeref {
|
||||||
region: self.region.fold_with(folder),
|
region: self.region.fold_with(folder),
|
||||||
mutbl: self.mutbl,
|
mutbl: self.mutbl,
|
||||||
target: self.target.fold_with(folder),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||||
self.region.visit_with(visitor) || self.target.visit_with(visitor)
|
self.region.visit_with(visitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -889,22 +889,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check for overloaded autoderef method calls.
|
// Check for overloaded autoderef method calls.
|
||||||
if let Some(&Adjustment {
|
|
||||||
kind: Adjust::Deref(ref autoderefs), ..
|
|
||||||
}) = cx.tables.adjustments.get(&id) {
|
|
||||||
let mut source = cx.tables.expr_ty(expr);
|
let mut source = cx.tables.expr_ty(expr);
|
||||||
for &overloaded in autoderefs {
|
for adjustment in cx.tables.expr_adjustments(expr) {
|
||||||
if let Some(deref) = overloaded {
|
if let Adjust::Deref(Some(deref)) = adjustment.kind {
|
||||||
let (def_id, substs) = deref.method_call(cx.tcx, source);
|
let (def_id, substs) = deref.method_call(cx.tcx, source);
|
||||||
if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) {
|
if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
source = deref.target;
|
|
||||||
} else {
|
|
||||||
source = source.builtin_deref(true,
|
|
||||||
ty::LvaluePreference::NoPreference).unwrap().ty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
source = adjustment.target;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for method calls and overloaded operators.
|
// Check for method calls and overloaded operators.
|
||||||
|
|
|
@ -468,19 +468,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(adjustment) = cx.tables.adjustments.get(&e.id) {
|
for adj in cx.tables.expr_adjustments(e) {
|
||||||
match adjustment.autoref {
|
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
|
||||||
Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => {
|
let msg = match m {
|
||||||
cx.span_lint(UNUSED_ALLOCATION,
|
hir::MutImmutable => "unnecessary allocation, use & instead",
|
||||||
e.span,
|
hir::MutMutable => "unnecessary allocation, use &mut instead"
|
||||||
"unnecessary allocation, use & instead");
|
};
|
||||||
}
|
cx.span_lint(UNUSED_ALLOCATION, e.span, msg);
|
||||||
Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => {
|
|
||||||
cx.span_lint(UNUSED_ALLOCATION,
|
|
||||||
e.span,
|
|
||||||
"unnecessary allocation, use &mut instead");
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ use hair::cx::to_ref::ToRef;
|
||||||
use rustc::hir::def::{Def, CtorKind};
|
use rustc::hir::def::{Def, CtorKind};
|
||||||
use rustc::middle::const_val::ConstVal;
|
use rustc::middle::const_val::ConstVal;
|
||||||
use rustc::ty::{self, AdtKind, VariantDef, Ty};
|
use rustc::ty::{self, AdtKind, VariantDef, Ty};
|
||||||
|
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||||
use rustc::ty::cast::CastKind as TyCastKind;
|
use rustc::ty::cast::CastKind as TyCastKind;
|
||||||
use rustc::ty::subst::Subst;
|
use rustc::ty::subst::Subst;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
@ -32,177 +33,13 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||||
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
|
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
|
||||||
|
|
||||||
let mut expr = make_mirror_unadjusted(cx, self);
|
let mut expr = make_mirror_unadjusted(cx, self);
|
||||||
let adj = cx.tables().adjustments.get(&self.id);
|
|
||||||
|
|
||||||
debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
|
|
||||||
expr,
|
|
||||||
adj);
|
|
||||||
|
|
||||||
// Now apply adjustments, if any.
|
// Now apply adjustments, if any.
|
||||||
match adj.map(|adj| (&adj.kind, adj.target)) {
|
for adjustment in cx.tables().expr_adjustments(self) {
|
||||||
None => {}
|
debug!("make_mirror: expr={:?} applying adjustment={:?}",
|
||||||
Some((&ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => {
|
expr,
|
||||||
expr = Expr {
|
adjustment);
|
||||||
temp_lifetime: temp_lifetime,
|
expr = apply_adjustment(cx, self, expr, adjustment);
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: adjusted_ty,
|
|
||||||
span: self.span,
|
|
||||||
kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Some((&ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => {
|
|
||||||
expr = Expr {
|
|
||||||
temp_lifetime: temp_lifetime,
|
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: adjusted_ty,
|
|
||||||
span: self.span,
|
|
||||||
kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Some((&ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => {
|
|
||||||
expr = Expr {
|
|
||||||
temp_lifetime: temp_lifetime,
|
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: adjusted_ty,
|
|
||||||
span: self.span,
|
|
||||||
kind: ExprKind::ClosureFnPointer { source: expr.to_ref() },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Some((&ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
|
|
||||||
expr = Expr {
|
|
||||||
temp_lifetime: temp_lifetime,
|
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: adjusted_ty,
|
|
||||||
span: self.span,
|
|
||||||
kind: ExprKind::NeverToAny { source: expr.to_ref() },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Some((&ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => {
|
|
||||||
expr = Expr {
|
|
||||||
temp_lifetime: temp_lifetime,
|
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: adjusted_ty,
|
|
||||||
span: self.span,
|
|
||||||
kind: ExprKind::Cast { source: expr.to_ref() },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Some((&ty::adjustment::Adjust::Deref(ref autoderefs), _)) => {
|
|
||||||
for &overloaded in autoderefs {
|
|
||||||
let source = expr.ty;
|
|
||||||
let target;
|
|
||||||
let kind = if let Some(deref) = overloaded {
|
|
||||||
debug!("make_mirror: overloaded autoderef ({:?})", deref);
|
|
||||||
|
|
||||||
expr = Expr {
|
|
||||||
temp_lifetime: temp_lifetime,
|
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: cx.tcx.mk_ref(deref.region,
|
|
||||||
ty::TypeAndMut {
|
|
||||||
ty: source,
|
|
||||||
mutbl: deref.mutbl,
|
|
||||||
}),
|
|
||||||
span: expr.span,
|
|
||||||
kind: ExprKind::Borrow {
|
|
||||||
region: deref.region,
|
|
||||||
borrow_kind: to_borrow_kind(deref.mutbl),
|
|
||||||
arg: expr.to_ref(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
target = deref.target;
|
|
||||||
|
|
||||||
let call = deref.method_call(cx.tcx, source);
|
|
||||||
overloaded_lvalue(cx,
|
|
||||||
self,
|
|
||||||
deref.target,
|
|
||||||
Some(call),
|
|
||||||
PassArgs::ByRef,
|
|
||||||
expr.to_ref(),
|
|
||||||
vec![])
|
|
||||||
} else {
|
|
||||||
match source.builtin_deref(true,
|
|
||||||
ty::LvaluePreference::NoPreference) {
|
|
||||||
Some(mt) => {
|
|
||||||
target = mt.ty;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
span_bug!(self.span, "autoderef for {} failed: {}",
|
|
||||||
self.id, source);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
debug!("make_mirror: built-in autoderef");
|
|
||||||
ExprKind::Deref { arg: expr.to_ref() }
|
|
||||||
};
|
|
||||||
debug!("make_mirror: autoderef target={:?}", target);
|
|
||||||
expr = Expr {
|
|
||||||
temp_lifetime: temp_lifetime,
|
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: target,
|
|
||||||
span: self.span,
|
|
||||||
kind: kind,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(adj) = adj {
|
|
||||||
if let Some(autoref) = adj.autoref {
|
|
||||||
let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
|
|
||||||
match autoref {
|
|
||||||
ty::adjustment::AutoBorrow::Ref(r, m) => {
|
|
||||||
expr = Expr {
|
|
||||||
temp_lifetime: temp_lifetime,
|
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: adjusted_ty,
|
|
||||||
span: self.span,
|
|
||||||
kind: ExprKind::Borrow {
|
|
||||||
region: r,
|
|
||||||
borrow_kind: to_borrow_kind(m),
|
|
||||||
arg: expr.to_ref(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
ty::adjustment::AutoBorrow::RawPtr(m) => {
|
|
||||||
// Convert this to a suitable `&foo` and
|
|
||||||
// then an unsafe coercion. Limit the region to be just this
|
|
||||||
// expression.
|
|
||||||
let region = ty::ReScope(expr_extent);
|
|
||||||
let region = cx.tcx.mk_region(region);
|
|
||||||
expr = Expr {
|
|
||||||
temp_lifetime: temp_lifetime,
|
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: cx.tcx.mk_ref(region,
|
|
||||||
ty::TypeAndMut {
|
|
||||||
ty: expr.ty,
|
|
||||||
mutbl: m,
|
|
||||||
}),
|
|
||||||
span: self.span,
|
|
||||||
kind: ExprKind::Borrow {
|
|
||||||
region: region,
|
|
||||||
borrow_kind: to_borrow_kind(m),
|
|
||||||
arg: expr.to_ref(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
expr = Expr {
|
|
||||||
temp_lifetime: temp_lifetime,
|
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: adjusted_ty,
|
|
||||||
span: self.span,
|
|
||||||
kind: ExprKind::Cast { source: expr.to_ref() },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if adj.unsize {
|
|
||||||
expr = Expr {
|
|
||||||
temp_lifetime: temp_lifetime,
|
|
||||||
temp_lifetime_was_shrunk: was_shrunk,
|
|
||||||
ty: adj.target,
|
|
||||||
span: self.span,
|
|
||||||
kind: ExprKind::Unsize { source: expr.to_ref() },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, wrap this up in the expr's scope.
|
// Next, wrap this up in the expr's scope.
|
||||||
|
@ -236,6 +73,102 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
|
hir_expr: &'tcx hir::Expr,
|
||||||
|
mut expr: Expr<'tcx>,
|
||||||
|
adjustment: &Adjustment<'tcx>)
|
||||||
|
-> Expr<'tcx> {
|
||||||
|
let Expr { temp_lifetime, temp_lifetime_was_shrunk, span, .. } = expr;
|
||||||
|
let kind = match adjustment.kind {
|
||||||
|
Adjust::ReifyFnPointer => {
|
||||||
|
ExprKind::ReifyFnPointer { source: expr.to_ref() }
|
||||||
|
}
|
||||||
|
Adjust::UnsafeFnPointer => {
|
||||||
|
ExprKind::UnsafeFnPointer { source: expr.to_ref() }
|
||||||
|
}
|
||||||
|
Adjust::ClosureFnPointer => {
|
||||||
|
ExprKind::ClosureFnPointer { source: expr.to_ref() }
|
||||||
|
}
|
||||||
|
Adjust::NeverToAny => {
|
||||||
|
ExprKind::NeverToAny { source: expr.to_ref() }
|
||||||
|
}
|
||||||
|
Adjust::MutToConstPointer => {
|
||||||
|
ExprKind::Cast { source: expr.to_ref() }
|
||||||
|
}
|
||||||
|
Adjust::Deref(None) => {
|
||||||
|
ExprKind::Deref { arg: expr.to_ref() }
|
||||||
|
}
|
||||||
|
Adjust::Deref(Some(deref)) => {
|
||||||
|
let call = deref.method_call(cx.tcx, expr.ty);
|
||||||
|
|
||||||
|
expr = Expr {
|
||||||
|
temp_lifetime,
|
||||||
|
temp_lifetime_was_shrunk,
|
||||||
|
ty: cx.tcx.mk_ref(deref.region,
|
||||||
|
ty::TypeAndMut {
|
||||||
|
ty: expr.ty,
|
||||||
|
mutbl: deref.mutbl,
|
||||||
|
}),
|
||||||
|
span,
|
||||||
|
kind: ExprKind::Borrow {
|
||||||
|
region: deref.region,
|
||||||
|
borrow_kind: to_borrow_kind(deref.mutbl),
|
||||||
|
arg: expr.to_ref(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
overloaded_lvalue(cx,
|
||||||
|
hir_expr,
|
||||||
|
adjustment.target,
|
||||||
|
Some(call),
|
||||||
|
PassArgs::ByValue,
|
||||||
|
expr.to_ref(),
|
||||||
|
vec![])
|
||||||
|
}
|
||||||
|
Adjust::Borrow(AutoBorrow::Ref(r, m)) => {
|
||||||
|
ExprKind::Borrow {
|
||||||
|
region: r,
|
||||||
|
borrow_kind: to_borrow_kind(m),
|
||||||
|
arg: expr.to_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Adjust::Borrow(AutoBorrow::RawPtr(m)) => {
|
||||||
|
// Convert this to a suitable `&foo` and
|
||||||
|
// then an unsafe coercion. Limit the region to be just this
|
||||||
|
// expression.
|
||||||
|
let region = ty::ReScope(CodeExtent::Misc(hir_expr.id));
|
||||||
|
let region = cx.tcx.mk_region(region);
|
||||||
|
expr = Expr {
|
||||||
|
temp_lifetime,
|
||||||
|
temp_lifetime_was_shrunk,
|
||||||
|
ty: cx.tcx.mk_ref(region,
|
||||||
|
ty::TypeAndMut {
|
||||||
|
ty: expr.ty,
|
||||||
|
mutbl: m,
|
||||||
|
}),
|
||||||
|
span,
|
||||||
|
kind: ExprKind::Borrow {
|
||||||
|
region: region,
|
||||||
|
borrow_kind: to_borrow_kind(m),
|
||||||
|
arg: expr.to_ref(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ExprKind::Cast { source: expr.to_ref() }
|
||||||
|
}
|
||||||
|
Adjust::Unsize => {
|
||||||
|
ExprKind::Unsize { source: expr.to_ref() }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Expr {
|
||||||
|
temp_lifetime,
|
||||||
|
temp_lifetime_was_shrunk,
|
||||||
|
ty: adjustment.target,
|
||||||
|
span,
|
||||||
|
kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
expr: &'tcx hir::Expr)
|
expr: &'tcx hir::Expr)
|
||||||
-> Expr<'tcx> {
|
-> Expr<'tcx> {
|
||||||
|
|
|
@ -441,17 +441,21 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
|
||||||
fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
|
fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
|
||||||
use rustc::ty::adjustment::*;
|
use rustc::ty::adjustment::*;
|
||||||
|
|
||||||
match v.tables.adjustments.get(&e.id).map(|adj| &adj.kind) {
|
for adjustment in v.tables.expr_adjustments(e) {
|
||||||
None |
|
match adjustment.kind {
|
||||||
Some(&Adjust::NeverToAny) |
|
Adjust::NeverToAny |
|
||||||
Some(&Adjust::ReifyFnPointer) |
|
Adjust::ReifyFnPointer |
|
||||||
Some(&Adjust::UnsafeFnPointer) |
|
Adjust::UnsafeFnPointer |
|
||||||
Some(&Adjust::ClosureFnPointer) |
|
Adjust::ClosureFnPointer |
|
||||||
Some(&Adjust::MutToConstPointer) => {}
|
Adjust::MutToConstPointer |
|
||||||
|
Adjust::Borrow(_) |
|
||||||
|
Adjust::Unsize => {}
|
||||||
|
|
||||||
Some(&Adjust::Deref(ref autoderefs)) => {
|
Adjust::Deref(ref overloaded) => {
|
||||||
if autoderefs.iter().any(|overloaded| overloaded.is_some()) {
|
if overloaded.is_some() {
|
||||||
v.promotable = false;
|
v.promotable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,13 @@ use rustc::traits;
|
||||||
use rustc::ty::{self, Ty, TraitRef};
|
use rustc::ty::{self, Ty, TraitRef};
|
||||||
use rustc::ty::{ToPredicate, TypeFoldable};
|
use rustc::ty::{ToPredicate, TypeFoldable};
|
||||||
use rustc::ty::{LvaluePreference, NoPreference};
|
use rustc::ty::{LvaluePreference, NoPreference};
|
||||||
use rustc::ty::adjustment::{AutoBorrow, OverloadedDeref};
|
use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
|
||||||
|
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use syntax::symbol::Symbol;
|
use syntax::symbol::Symbol;
|
||||||
|
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
enum AutoderefKind {
|
enum AutoderefKind {
|
||||||
Builtin,
|
Builtin,
|
||||||
|
@ -152,25 +154,26 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
|
||||||
self.steps.len()
|
self.steps.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the steps required in adjustments (overloaded deref calls).
|
/// Returns the adjustment steps.
|
||||||
pub fn adjust_steps(&self, pref: LvaluePreference)
|
pub fn adjust_steps(&self, pref: LvaluePreference)
|
||||||
-> Vec<Option<OverloadedDeref<'tcx>>> {
|
-> Vec<Adjustment<'tcx>> {
|
||||||
self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref))
|
self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference)
|
pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference)
|
||||||
-> InferOk<'tcx, Vec<Option<OverloadedDeref<'tcx>>>> {
|
-> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
|
||||||
let mut obligations = vec![];
|
let mut obligations = vec![];
|
||||||
|
let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty)
|
||||||
|
.chain(iter::once(self.cur_ty));
|
||||||
let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| {
|
let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| {
|
||||||
if let AutoderefKind::Overloaded = kind {
|
if let AutoderefKind::Overloaded = kind {
|
||||||
self.fcx.try_overloaded_deref(self.span, source, pref)
|
self.fcx.try_overloaded_deref(self.span, source, pref)
|
||||||
.and_then(|InferOk { value: (_, method), obligations: o }| {
|
.and_then(|InferOk { value: method, obligations: o }| {
|
||||||
obligations.extend(o);
|
obligations.extend(o);
|
||||||
if let ty::TyRef(region, mt) = method.sig.output().sty {
|
if let ty::TyRef(region, mt) = method.sig.output().sty {
|
||||||
Some(OverloadedDeref {
|
Some(OverloadedDeref {
|
||||||
region,
|
region,
|
||||||
mutbl: mt.mutbl,
|
mutbl: mt.mutbl,
|
||||||
target: mt.ty
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -179,6 +182,11 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
}).zip(targets).map(|(autoderef, target)| {
|
||||||
|
Adjustment {
|
||||||
|
kind: Adjust::Deref(autoderef),
|
||||||
|
target
|
||||||
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
InferOk {
|
InferOk {
|
||||||
|
@ -213,9 +221,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
base_ty: Ty<'tcx>,
|
base_ty: Ty<'tcx>,
|
||||||
pref: LvaluePreference)
|
pref: LvaluePreference)
|
||||||
-> Option<InferOk<'tcx,
|
-> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
|
||||||
(Option<AutoBorrow<'tcx>>,
|
|
||||||
MethodCallee<'tcx>)>> {
|
|
||||||
self.try_overloaded_lvalue_op(span, base_ty, &[], pref, LvalueOp::Deref)
|
self.try_overloaded_lvalue_op(span, base_ty, &[], pref, LvalueOp::Deref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ use hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc::{infer, traits};
|
use rustc::{infer, traits};
|
||||||
use rustc::ty::{self, TyCtxt, LvaluePreference, Ty};
|
use rustc::ty::{self, TyCtxt, LvaluePreference, Ty};
|
||||||
use rustc::ty::subst::Subst;
|
use rustc::ty::subst::Subst;
|
||||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref};
|
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
use syntax::symbol::Symbol;
|
use syntax::symbol::Symbol;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -96,8 +96,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// If the callee is a bare function or a closure, then we're all set.
|
// If the callee is a bare function or a closure, then we're all set.
|
||||||
match adjusted_ty.sty {
|
match adjusted_ty.sty {
|
||||||
ty::TyFnDef(..) | ty::TyFnPtr(_) => {
|
ty::TyFnDef(..) | ty::TyFnPtr(_) => {
|
||||||
let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
||||||
self.apply_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty);
|
self.apply_adjustments(callee_expr, adjustments);
|
||||||
return Some(CallStep::Builtin(adjusted_ty));
|
return Some(CallStep::Builtin(adjusted_ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,13 +113,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
infer::FnCall,
|
infer::FnCall,
|
||||||
&closure_ty)
|
&closure_ty)
|
||||||
.0;
|
.0;
|
||||||
let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
||||||
self.record_deferred_call_resolution(def_id, DeferredCallResolution {
|
self.record_deferred_call_resolution(def_id, DeferredCallResolution {
|
||||||
call_expr: call_expr,
|
call_expr,
|
||||||
callee_expr: callee_expr,
|
callee_expr,
|
||||||
adjusted_ty: adjusted_ty,
|
adjusted_ty,
|
||||||
autoderefs: autoderefs,
|
adjustments,
|
||||||
fn_sig: fn_sig.clone(),
|
fn_sig,
|
||||||
closure_def_id: def_id,
|
closure_def_id: def_id,
|
||||||
});
|
});
|
||||||
return Some(CallStep::DeferredClosure(fn_sig));
|
return Some(CallStep::DeferredClosure(fn_sig));
|
||||||
|
@ -142,13 +142,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| {
|
self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| {
|
||||||
let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
||||||
self.apply_adjustment(callee_expr.id, Adjustment {
|
adjustments.extend(autoref);
|
||||||
kind: Adjust::Deref(autoderefs),
|
self.apply_adjustments(callee_expr, adjustments);
|
||||||
autoref,
|
|
||||||
unsize: false,
|
|
||||||
target: method.sig.inputs()[0]
|
|
||||||
});
|
|
||||||
CallStep::Overloaded(method)
|
CallStep::Overloaded(method)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -156,25 +152,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
fn try_overloaded_call_traits(&self,
|
fn try_overloaded_call_traits(&self,
|
||||||
call_expr: &hir::Expr,
|
call_expr: &hir::Expr,
|
||||||
adjusted_ty: Ty<'tcx>)
|
adjusted_ty: Ty<'tcx>)
|
||||||
-> Option<(Option<AutoBorrow<'tcx>>,
|
-> Option<(Option<Adjustment<'tcx>>,
|
||||||
MethodCallee<'tcx>)> {
|
MethodCallee<'tcx>)> {
|
||||||
// Try the options that are least restrictive on the caller first.
|
// Try the options that are least restrictive on the caller first.
|
||||||
for &(opt_trait_def_id, method_name) in
|
for &(opt_trait_def_id, method_name, borrow) in
|
||||||
&[(self.tcx.lang_items.fn_trait(), Symbol::intern("call")),
|
&[(self.tcx.lang_items.fn_trait(), Symbol::intern("call"), true),
|
||||||
(self.tcx.lang_items.fn_mut_trait(), Symbol::intern("call_mut")),
|
(self.tcx.lang_items.fn_mut_trait(), Symbol::intern("call_mut"), true),
|
||||||
(self.tcx.lang_items.fn_once_trait(), Symbol::intern("call_once"))] {
|
(self.tcx.lang_items.fn_once_trait(), Symbol::intern("call_once"), false)] {
|
||||||
let trait_def_id = match opt_trait_def_id {
|
let trait_def_id = match opt_trait_def_id {
|
||||||
Some(def_id) => def_id,
|
Some(def_id) => def_id,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.lookup_method_in_trait_adjusted(call_expr.span,
|
match self.lookup_method_in_trait(call_expr.span,
|
||||||
method_name,
|
method_name,
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
adjusted_ty,
|
adjusted_ty,
|
||||||
None) {
|
None) {
|
||||||
None => continue,
|
None => continue,
|
||||||
Some(ok) => return Some(self.register_infer_ok_obligations(ok))
|
Some(ok) => {
|
||||||
|
let method = self.register_infer_ok_obligations(ok);
|
||||||
|
let mut autoref = None;
|
||||||
|
if borrow {
|
||||||
|
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
|
||||||
|
autoref = Some(Adjustment {
|
||||||
|
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
|
||||||
|
target: method.sig.inputs()[0]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some((autoref, method));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +325,7 @@ pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> {
|
||||||
call_expr: &'gcx hir::Expr,
|
call_expr: &'gcx hir::Expr,
|
||||||
callee_expr: &'gcx hir::Expr,
|
callee_expr: &'gcx hir::Expr,
|
||||||
adjusted_ty: Ty<'tcx>,
|
adjusted_ty: Ty<'tcx>,
|
||||||
autoderefs: Vec<Option<OverloadedDeref<'tcx>>>,
|
adjustments: Vec<Adjustment<'tcx>>,
|
||||||
fn_sig: ty::FnSig<'tcx>,
|
fn_sig: ty::FnSig<'tcx>,
|
||||||
closure_def_id: DefId,
|
closure_def_id: DefId,
|
||||||
}
|
}
|
||||||
|
@ -353,12 +361,9 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
|
||||||
|
|
||||||
fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output());
|
fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output());
|
||||||
|
|
||||||
fcx.apply_adjustment(self.callee_expr.id, Adjustment {
|
let mut adjustments = self.adjustments;
|
||||||
kind: Adjust::Deref(self.autoderefs),
|
adjustments.extend(autoref);
|
||||||
autoref,
|
fcx.apply_adjustments(self.callee_expr, adjustments);
|
||||||
unsize: false,
|
|
||||||
target: method_sig.inputs()[0]
|
|
||||||
});
|
|
||||||
|
|
||||||
fcx.write_method_call(self.call_expr.id, method_callee);
|
fcx.write_method_call(self.call_expr.id, method_callee);
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>;
|
type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
|
||||||
|
|
||||||
fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
|
fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
|
||||||
to_mutbl: hir::Mutability)
|
to_mutbl: hir::Mutability)
|
||||||
|
@ -108,24 +108,18 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn identity<'tcx>(target: Ty<'tcx>) -> Adjustment<'tcx> {
|
fn identity(_: Ty) -> Vec<Adjustment> { vec![] }
|
||||||
simple(Adjust::Deref(vec![]))(target)
|
|
||||||
|
fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
|
||||||
|
move |target| vec![Adjustment { kind, target }]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Adjustment<'tcx> {
|
fn success<'tcx>(adj: Vec<Adjustment<'tcx>>,
|
||||||
move |target| Adjustment {
|
target: Ty<'tcx>,
|
||||||
kind,
|
|
||||||
autoref: None,
|
|
||||||
unsize: false,
|
|
||||||
target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn success<'tcx>(adj: Adjustment<'tcx>,
|
|
||||||
obligations: traits::PredicateObligations<'tcx>)
|
obligations: traits::PredicateObligations<'tcx>)
|
||||||
-> CoerceResult<'tcx> {
|
-> CoerceResult<'tcx> {
|
||||||
Ok(InferOk {
|
Ok(InferOk {
|
||||||
value: adj,
|
value: (adj, target),
|
||||||
obligations
|
obligations
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -153,10 +147,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
/// Unify two types (using sub or lub) and produce a specific coercion.
|
/// Unify two types (using sub or lub) and produce a specific coercion.
|
||||||
fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F)
|
fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F)
|
||||||
-> CoerceResult<'tcx>
|
-> CoerceResult<'tcx>
|
||||||
where F: FnOnce(Ty<'tcx>) -> Adjustment<'tcx>
|
where F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>
|
||||||
{
|
{
|
||||||
self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| {
|
self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| {
|
||||||
success(f(ty), obligations)
|
success(f(ty), ty, obligations)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +160,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// Just ignore error types.
|
// Just ignore error types.
|
||||||
if a.references_error() || b.references_error() {
|
if a.references_error() || b.references_error() {
|
||||||
return success(identity(b), vec![]);
|
return success(vec![], b, vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.is_never() {
|
if a.is_never() {
|
||||||
|
@ -185,7 +179,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
TypeVariableOrigin::AdjustmentType(self.cause.span));
|
TypeVariableOrigin::AdjustmentType(self.cause.span));
|
||||||
self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
|
self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
|
||||||
} else {
|
} else {
|
||||||
success(simple(Adjust::NeverToAny)(b), vec![])
|
success(simple(Adjust::NeverToAny)(b), b, vec![])
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,34 +401,31 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
// `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
|
// `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
|
||||||
// which is a borrow.
|
// which is a borrow.
|
||||||
assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U
|
assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U
|
||||||
return success(identity(ty), obligations);
|
return success(vec![], ty, obligations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pref = LvaluePreference::from_mutbl(mt_b.mutbl);
|
||||||
|
let InferOk { value: mut adjustments, obligations: o }
|
||||||
|
= autoderef.adjust_steps_as_infer_ok(pref);
|
||||||
|
obligations.extend(o);
|
||||||
|
obligations.extend(autoderef.into_obligations());
|
||||||
|
|
||||||
// Now apply the autoref. We have to extract the region out of
|
// Now apply the autoref. We have to extract the region out of
|
||||||
// the final ref type we got.
|
// the final ref type we got.
|
||||||
let r_borrow = match ty.sty {
|
let r_borrow = match ty.sty {
|
||||||
ty::TyRef(r_borrow, _) => r_borrow,
|
ty::TyRef(r_borrow, _) => r_borrow,
|
||||||
_ => span_bug!(span, "expected a ref type, got {:?}", ty),
|
_ => span_bug!(span, "expected a ref type, got {:?}", ty),
|
||||||
};
|
};
|
||||||
let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl));
|
adjustments.push(Adjustment {
|
||||||
|
kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)),
|
||||||
let pref = LvaluePreference::from_mutbl(mt_b.mutbl);
|
|
||||||
let InferOk { value: autoderefs, obligations: o }
|
|
||||||
= autoderef.adjust_steps_as_infer_ok(pref);
|
|
||||||
obligations.extend(o);
|
|
||||||
obligations.extend(autoderef.into_obligations());
|
|
||||||
|
|
||||||
debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}",
|
|
||||||
ty,
|
|
||||||
autoderefs,
|
|
||||||
autoref);
|
|
||||||
|
|
||||||
success(Adjustment {
|
|
||||||
kind: Adjust::Deref(autoderefs),
|
|
||||||
autoref,
|
|
||||||
unsize: false,
|
|
||||||
target: ty
|
target: ty
|
||||||
}, obligations)
|
});
|
||||||
|
|
||||||
|
debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}",
|
||||||
|
ty,
|
||||||
|
adjustments);
|
||||||
|
|
||||||
|
success(adjustments, ty, obligations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -459,21 +450,40 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
// that, at which point we will need extra checks on the target here.
|
// that, at which point we will need extra checks on the target here.
|
||||||
|
|
||||||
// Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
|
// Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
|
||||||
let (source, reborrow) = match (&source.sty, &target.sty) {
|
let reborrow = match (&source.sty, &target.sty) {
|
||||||
(&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
|
(&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
|
||||||
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
||||||
|
|
||||||
let coercion = Coercion(self.cause.span);
|
let coercion = Coercion(self.cause.span);
|
||||||
let r_borrow = self.next_region_var(coercion);
|
let r_borrow = self.next_region_var(coercion);
|
||||||
(mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)))
|
Some((Adjustment {
|
||||||
|
kind: Adjust::Deref(None),
|
||||||
|
target: mt_a.ty
|
||||||
|
}, Adjustment {
|
||||||
|
kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)),
|
||||||
|
target: self.tcx.mk_ref(r_borrow, ty::TypeAndMut {
|
||||||
|
mutbl: mt_b.mutbl,
|
||||||
|
ty: mt_a.ty
|
||||||
|
})
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
(&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
|
(&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
|
||||||
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
|
||||||
(mt_a.ty, Some(AutoBorrow::RawPtr(mt_b.mutbl)))
|
|
||||||
|
Some((Adjustment {
|
||||||
|
kind: Adjust::Deref(None),
|
||||||
|
target: mt_a.ty
|
||||||
|
}, Adjustment {
|
||||||
|
kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b.mutbl)),
|
||||||
|
target: self.tcx.mk_ptr(ty::TypeAndMut {
|
||||||
|
mutbl: mt_b.mutbl,
|
||||||
|
ty: mt_a.ty
|
||||||
|
})
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
_ => (source, None),
|
_ => None,
|
||||||
};
|
};
|
||||||
let coerce_source = source.adjust_for_autoref(self.tcx, reborrow);
|
let coerce_source = reborrow.as_ref().map_or(source, |&(_, ref r)| r.target);
|
||||||
|
|
||||||
// Setup either a subtyping or a LUB relationship between
|
// Setup either a subtyping or a LUB relationship between
|
||||||
// the `CoerceUnsized` target type and the expected type.
|
// the `CoerceUnsized` target type and the expected type.
|
||||||
|
@ -481,11 +491,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
// for the former and let type inference do the rest.
|
// for the former and let type inference do the rest.
|
||||||
let origin = TypeVariableOrigin::MiscVariable(self.cause.span);
|
let origin = TypeVariableOrigin::MiscVariable(self.cause.span);
|
||||||
let coerce_target = self.next_ty_var(origin);
|
let coerce_target = self.next_ty_var(origin);
|
||||||
let mut coercion = self.unify_and(coerce_target, target, |target| Adjustment {
|
let mut coercion = self.unify_and(coerce_target, target, |target| {
|
||||||
kind: Adjust::Deref(if reborrow.is_some() { vec![None] } else { vec![] }),
|
let unsize = Adjustment {
|
||||||
autoref: reborrow,
|
kind: Adjust::Unsize,
|
||||||
unsize: true,
|
|
||||||
target
|
target
|
||||||
|
};
|
||||||
|
match reborrow {
|
||||||
|
None => vec![unsize],
|
||||||
|
Some((ref deref, ref autoref)) => {
|
||||||
|
vec![deref.clone(), autoref.clone(), unsize]
|
||||||
|
}
|
||||||
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut selcx = traits::SelectionContext::new(self);
|
let mut selcx = traits::SelectionContext::new(self);
|
||||||
|
@ -546,8 +562,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
to_unsafe: F,
|
to_unsafe: F,
|
||||||
normal: G)
|
normal: G)
|
||||||
-> CoerceResult<'tcx>
|
-> CoerceResult<'tcx>
|
||||||
where F: FnOnce(Ty<'tcx>) -> Adjustment<'tcx>,
|
where F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
||||||
G: FnOnce(Ty<'tcx>) -> Adjustment<'tcx>
|
G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>
|
||||||
{
|
{
|
||||||
if let ty::TyFnPtr(fn_ty_b) = b.sty {
|
if let ty::TyFnPtr(fn_ty_b) = b.sty {
|
||||||
match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) {
|
match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) {
|
||||||
|
@ -668,11 +684,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
// representation, we still register an Adjust::DerefRef so that
|
// representation, we still register an Adjust::DerefRef so that
|
||||||
// regionck knows that the region for `a` must be valid here.
|
// regionck knows that the region for `a` must be valid here.
|
||||||
if is_ref {
|
if is_ref {
|
||||||
self.unify_and(a_unsafe, b, |target| Adjustment {
|
self.unify_and(a_unsafe, b, |target| {
|
||||||
kind: Adjust::Deref(vec![None]),
|
vec![Adjustment {
|
||||||
autoref: Some(AutoBorrow::RawPtr(mutbl_b)),
|
kind: Adjust::Deref(None),
|
||||||
unsize: false,
|
target: mt_a.ty
|
||||||
|
}, Adjustment {
|
||||||
|
kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)),
|
||||||
target
|
target
|
||||||
|
}]
|
||||||
})
|
})
|
||||||
} else if mt_a.mutbl != mutbl_b {
|
} else if mt_a.mutbl != mutbl_b {
|
||||||
self.unify_and(a_unsafe, b, simple(Adjust::MutToConstPointer))
|
self.unify_and(a_unsafe, b, simple(Adjust::MutToConstPointer))
|
||||||
|
@ -707,12 +726,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let coerce = Coerce::new(self, cause);
|
let coerce = Coerce::new(self, cause);
|
||||||
let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
|
let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
|
||||||
|
|
||||||
let adjustment = self.register_infer_ok_obligations(ok);
|
let (adjustments, _) = self.register_infer_ok_obligations(ok);
|
||||||
self.apply_adjustment(expr.id, adjustment);
|
self.apply_adjustments(expr, adjustments);
|
||||||
|
|
||||||
// We should now have added sufficient adjustments etc to
|
|
||||||
// ensure that the type of expression, post-adjustment, is
|
|
||||||
// a subtype of target.
|
|
||||||
Ok(target)
|
Ok(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,12 +796,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) {
|
for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) {
|
||||||
// The only adjustment that can produce an fn item is
|
// The only adjustment that can produce an fn item is
|
||||||
// `NeverToAny`, so this should always be valid.
|
// `NeverToAny`, so this should always be valid.
|
||||||
self.apply_adjustment(expr.id, Adjustment {
|
self.apply_adjustments(expr, vec![Adjustment {
|
||||||
kind: Adjust::ReifyFnPointer,
|
kind: Adjust::ReifyFnPointer,
|
||||||
autoref: None,
|
|
||||||
unsize: false,
|
|
||||||
target: fn_ptr
|
target: fn_ptr
|
||||||
});
|
}]);
|
||||||
}
|
}
|
||||||
return Ok(fn_ptr);
|
return Ok(fn_ptr);
|
||||||
}
|
}
|
||||||
|
@ -803,9 +816,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty));
|
let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty));
|
||||||
match result {
|
match result {
|
||||||
Ok(ok) => {
|
Ok(ok) => {
|
||||||
let adjustment = self.register_infer_ok_obligations(ok);
|
let (adjustments, target) = self.register_infer_ok_obligations(ok);
|
||||||
let target = adjustment.target;
|
self.apply_adjustments(new, adjustments);
|
||||||
self.apply_adjustment(new.id, adjustment);
|
|
||||||
return Ok(target);
|
return Ok(target);
|
||||||
}
|
}
|
||||||
Err(e) => first_error = Some(e),
|
Err(e) => first_error = Some(e),
|
||||||
|
@ -817,26 +829,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// previous expressions, other than noop reborrows (ignoring lifetimes).
|
// previous expressions, other than noop reborrows (ignoring lifetimes).
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
let expr = expr.as_coercion_site();
|
let expr = expr.as_coercion_site();
|
||||||
let noop = match self.tables.borrow().adjustments.get(&expr.id) {
|
let noop = match self.tables.borrow().expr_adjustments(expr) {
|
||||||
Some(&Adjustment {
|
&[
|
||||||
kind: Adjust::Deref(ref autoderefs),
|
Adjustment { kind: Adjust::Deref(_), .. },
|
||||||
autoref: Some(AutoBorrow::Ref(_, mutbl_adj)),
|
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. }
|
||||||
unsize: false,
|
] => {
|
||||||
target: _
|
|
||||||
}) if autoderefs.len() == 1 => {
|
|
||||||
match self.node_ty(expr.id).sty {
|
match self.node_ty(expr.id).sty {
|
||||||
ty::TyRef(_, mt_orig) => {
|
ty::TyRef(_, mt_orig) => {
|
||||||
// Reborrow that we can safely ignore, because
|
// Reborrow that we can safely ignore, because
|
||||||
// the next adjustment can only be a DerefRef
|
// the next adjustment can only be a Deref
|
||||||
// which will be merged into it.
|
// which will be merged into it.
|
||||||
mutbl_adj == mt_orig.mutbl
|
mutbl_adj == mt_orig.mutbl
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => true,
|
&[Adjustment { kind: Adjust::NeverToAny, .. }] | &[] => true,
|
||||||
Some(_) => false,
|
_ => false,
|
||||||
None => true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !noop {
|
if !noop {
|
||||||
|
@ -860,12 +869,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(ok) => {
|
Ok(ok) => {
|
||||||
let adjustment = self.register_infer_ok_obligations(ok);
|
let (adjustments, target) = self.register_infer_ok_obligations(ok);
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
let expr = expr.as_coercion_site();
|
let expr = expr.as_coercion_site();
|
||||||
self.apply_adjustment(expr.id, adjustment.clone());
|
self.apply_adjustments(expr, adjustments.clone());
|
||||||
}
|
}
|
||||||
Ok(adjustment.target)
|
Ok(target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use hir::def_id::DefId;
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::traits;
|
use rustc::traits;
|
||||||
use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
|
use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
|
||||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref};
|
||||||
use rustc::ty::fold::TypeFoldable;
|
use rustc::ty::fold::TypeFoldable;
|
||||||
use rustc::infer::{self, InferOk};
|
use rustc::infer::{self, InferOk};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -118,40 +118,49 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||||
unadjusted_self_ty: Ty<'tcx>,
|
unadjusted_self_ty: Ty<'tcx>,
|
||||||
pick: &probe::Pick<'tcx>)
|
pick: &probe::Pick<'tcx>)
|
||||||
-> Ty<'tcx> {
|
-> Ty<'tcx> {
|
||||||
let autoref = if let Some(mutbl) = pick.autoref {
|
// 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);
|
||||||
|
let (_, n) = autoderef.nth(pick.autoderefs).unwrap();
|
||||||
|
assert_eq!(n, pick.autoderefs);
|
||||||
|
|
||||||
|
let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
||||||
|
|
||||||
|
let mut target = autoderef.unambiguous_final_ty();
|
||||||
|
|
||||||
|
if let Some(mutbl) = pick.autoref {
|
||||||
let region = self.next_region_var(infer::Autoref(self.span));
|
let region = self.next_region_var(infer::Autoref(self.span));
|
||||||
Some(AutoBorrow::Ref(region, mutbl))
|
target = self.tcx.mk_ref(region, ty::TypeAndMut {
|
||||||
|
mutbl,
|
||||||
|
ty: target
|
||||||
|
});
|
||||||
|
adjustments.push(Adjustment {
|
||||||
|
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
|
||||||
|
target
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(unsize_target) = pick.unsize {
|
||||||
|
target = self.tcx.mk_ref(region, ty::TypeAndMut {
|
||||||
|
mutbl,
|
||||||
|
ty: unsize_target
|
||||||
|
});
|
||||||
|
adjustments.push(Adjustment {
|
||||||
|
kind: Adjust::Unsize,
|
||||||
|
target
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// No unsizing should be performed without autoref (at
|
// No unsizing should be performed without autoref (at
|
||||||
// least during method dispach). This is because we
|
// least during method dispach). This is because we
|
||||||
// currently only unsize `[T;N]` to `[T]`, and naturally
|
// currently only unsize `[T;N]` to `[T]`, and naturally
|
||||||
// that must occur being a reference.
|
// that must occur being a reference.
|
||||||
assert!(pick.unsize.is_none());
|
assert!(pick.unsize.is_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);
|
|
||||||
let (autoderefd_ty, n) = autoderef.nth(pick.autoderefs).unwrap();
|
|
||||||
assert_eq!(n, pick.autoderefs);
|
|
||||||
|
|
||||||
let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference);
|
|
||||||
|
|
||||||
autoderef.unambiguous_final_ty();
|
|
||||||
autoderef.finalize();
|
autoderef.finalize();
|
||||||
|
|
||||||
let target = pick.unsize.unwrap_or(autoderefd_ty);
|
// Write out the final adjustments.
|
||||||
let target = target.adjust_for_autoref(self.tcx, autoref);
|
self.apply_adjustments(self.self_expr, adjustments);
|
||||||
|
|
||||||
// Write out the final adjustment.
|
|
||||||
self.apply_adjustment(self.self_expr.id, Adjustment {
|
|
||||||
kind: Adjust::Deref(autoderefs),
|
|
||||||
autoref,
|
|
||||||
unsize: pick.unsize.is_some(),
|
|
||||||
target,
|
|
||||||
});
|
|
||||||
|
|
||||||
target
|
target
|
||||||
}
|
}
|
||||||
|
@ -436,17 +445,22 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||||
// Fix up the autoderefs. Autorefs can only occur immediately preceding
|
// Fix up the autoderefs. Autorefs can only occur immediately preceding
|
||||||
// overloaded lvalue ops, and will be fixed by them in order to get
|
// overloaded lvalue ops, and will be fixed by them in order to get
|
||||||
// the correct region.
|
// the correct region.
|
||||||
let expr_ty = self.node_ty(expr.id);
|
let mut source = self.node_ty(expr.id);
|
||||||
if let Some(adj) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) {
|
if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) {
|
||||||
if let Adjust::Deref(ref mut autoderefs) = adj.kind {
|
let pref = LvaluePreference::PreferMutLvalue;
|
||||||
let mut autoderef = self.autoderef(expr.span, expr_ty);
|
for adjustment in adjustments {
|
||||||
autoderef.nth(autoderefs.len()).unwrap_or_else(|| {
|
if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
|
||||||
span_bug!(expr.span,
|
if let Some(ok) = self.try_overloaded_deref(expr.span, source, pref) {
|
||||||
"expr was deref-able as {:?} but now isn't?",
|
let method = self.register_infer_ok_obligations(ok);
|
||||||
autoderefs);
|
if let ty::TyRef(region, mt) = method.sig.output().sty {
|
||||||
});
|
*deref = OverloadedDeref {
|
||||||
*autoderefs = autoderef.adjust_steps(LvaluePreference::PreferMutLvalue);
|
region,
|
||||||
autoderef.finalize();
|
mutbl: mt.mutbl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
source = adjustment.target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,7 +492,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let base_ty = self.tables.borrow().adjustments.get(&base_expr.id)
|
let base_ty = self.tables.borrow().expr_adjustments(base_expr).last()
|
||||||
.map_or_else(|| self.node_ty(expr.id), |adj| adj.target);
|
.map_or_else(|| self.node_ty(expr.id), |adj| adj.target);
|
||||||
let base_ty = self.resolve_type_vars_if_possible(&base_ty);
|
let base_ty = self.resolve_type_vars_if_possible(&base_ty);
|
||||||
|
|
||||||
|
@ -489,28 +503,43 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let method = self.try_overloaded_lvalue_op(
|
let method = self.try_overloaded_lvalue_op(
|
||||||
expr.span, base_ty, arg_tys, PreferMutLvalue, op);
|
expr.span, base_ty, arg_tys, PreferMutLvalue, op);
|
||||||
let ok = match method {
|
let method = match method {
|
||||||
Some(method) => method,
|
Some(ok) => self.register_infer_ok_obligations(ok),
|
||||||
None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed")
|
None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed")
|
||||||
};
|
};
|
||||||
let (_, method) = self.register_infer_ok_obligations(ok);
|
|
||||||
debug!("convert_lvalue_op_to_mutable: method={:?}", method);
|
debug!("convert_lvalue_op_to_mutable: method={:?}", method);
|
||||||
self.write_method_call(expr.id, method);
|
self.write_method_call(expr.id, method);
|
||||||
|
|
||||||
// Convert the autoref in the base expr to mutable with the correct
|
let (region, mutbl) = if let ty::TyRef(r, mt) = method.sig.inputs()[0].sty {
|
||||||
// region and mutability.
|
(r, mt.mutbl)
|
||||||
if let Some(&mut Adjustment {
|
|
||||||
ref mut target,
|
|
||||||
autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), ..
|
|
||||||
}) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) {
|
|
||||||
debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target);
|
|
||||||
|
|
||||||
*target = method.sig.inputs()[0];
|
|
||||||
if let ty::TyRef(r_, mt) = target.sty {
|
|
||||||
*r = r_;
|
|
||||||
*mutbl = mt.mutbl;
|
|
||||||
} else {
|
} else {
|
||||||
span_bug!(expr.span, "input to lvalue op is not a ref?");
|
span_bug!(expr.span, "input to lvalue op is not a ref?");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert the autoref in the base expr to mutable with the correct
|
||||||
|
// region and mutability.
|
||||||
|
let base_expr_ty = self.node_ty(base_expr.id);
|
||||||
|
if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) {
|
||||||
|
let mut source = base_expr_ty;
|
||||||
|
for adjustment in &mut adjustments[..] {
|
||||||
|
if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
|
||||||
|
debug!("convert_lvalue_op_to_mutable: converting autoref {:?}", adjustment);
|
||||||
|
adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
|
||||||
|
adjustment.target = self.tcx.mk_ref(region, ty::TypeAndMut {
|
||||||
|
ty: source,
|
||||||
|
mutbl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
source = adjustment.target;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have an autoref followed by unsizing at the end, fix the unsize target.
|
||||||
|
match adjustments[..] {
|
||||||
|
[.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
|
||||||
|
Adjustment { kind: Adjust::Unsize, ref mut target }] => {
|
||||||
|
*target = method.sig.inputs()[0];
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ use hir::def_id::DefId;
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::traits;
|
use rustc::traits;
|
||||||
use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
|
use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
|
||||||
use rustc::ty::adjustment::AutoBorrow;
|
|
||||||
use rustc::ty::subst::Subst;
|
use rustc::ty::subst::Subst;
|
||||||
use rustc::infer::{self, InferOk};
|
use rustc::infer::{self, InferOk};
|
||||||
|
|
||||||
|
@ -165,26 +164,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
supplied_method_types))
|
supplied_method_types))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `lookup_in_trait_adjusted` is used for overloaded operators.
|
/// `lookup_method_in_trait` is used for overloaded operators.
|
||||||
/// It does a very narrow slice of what the normal probe/confirm path does.
|
/// It does a very narrow slice of what the normal probe/confirm path does.
|
||||||
/// In particular, it doesn't really do any probing: it simply constructs
|
/// In particular, it doesn't really do any probing: it simply constructs
|
||||||
/// an obligation for aparticular trait with the given self-type and checks
|
/// an obligation for aparticular trait with the given self-type and checks
|
||||||
/// whether that trait is implemented.
|
/// whether that trait is implemented.
|
||||||
///
|
///
|
||||||
/// FIXME(#18741) -- It seems likely that we can consolidate some of this
|
/// FIXME(#18741) -- It seems likely that we can consolidate some of this
|
||||||
/// code with the other method-lookup code. In particular, autoderef on
|
/// code with the other method-lookup code. In particular, the second half
|
||||||
/// index is basically identical to autoderef with normal probes, except
|
/// of this method is basically the same as confirmation.
|
||||||
/// that the test also looks for built-in indexing. Also, the second half of
|
pub fn lookup_method_in_trait(&self,
|
||||||
/// this method is basically the same as confirmation.
|
|
||||||
pub fn lookup_method_in_trait_adjusted(&self,
|
|
||||||
span: Span,
|
span: Span,
|
||||||
m_name: ast::Name,
|
m_name: ast::Name,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
self_ty: ty::Ty<'tcx>,
|
self_ty: ty::Ty<'tcx>,
|
||||||
opt_input_types: Option<&[ty::Ty<'tcx>]>)
|
opt_input_types: Option<&[ty::Ty<'tcx>]>)
|
||||||
-> Option<InferOk<'tcx,
|
-> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
|
||||||
(Option<AutoBorrow<'tcx>>,
|
|
||||||
MethodCallee<'tcx>)>> {
|
|
||||||
debug!("lookup_in_trait_adjusted(self_ty={:?}, \
|
debug!("lookup_in_trait_adjusted(self_ty={:?}, \
|
||||||
m_name={}, trait_def_id={:?})",
|
m_name={}, trait_def_id={:?})",
|
||||||
self_ty,
|
self_ty,
|
||||||
|
@ -237,8 +232,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// NB: Instantiate late-bound regions first so that
|
// NB: Instantiate late-bound regions first so that
|
||||||
// `instantiate_type_scheme` can normalize associated types that
|
// `instantiate_type_scheme` can normalize associated types that
|
||||||
// may reference those regions.
|
// may reference those regions.
|
||||||
let original_method_ty = tcx.type_of(def_id);
|
let fn_sig = tcx.type_of(def_id).fn_sig();
|
||||||
let fn_sig = original_method_ty.fn_sig();
|
|
||||||
let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
|
let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
|
||||||
infer::FnCall,
|
infer::FnCall,
|
||||||
&fn_sig).0;
|
&fn_sig).0;
|
||||||
|
@ -249,11 +243,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let method_ty = tcx.mk_fn_def(def_id, substs, ty::Binder(fn_sig));
|
|
||||||
|
|
||||||
debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
|
|
||||||
method_ty,
|
|
||||||
obligation);
|
|
||||||
|
|
||||||
// Register obligations for the parameters. This will include the
|
// Register obligations for the parameters. This will include the
|
||||||
// `Self` parameter, which in turn has a bound of the main trait,
|
// `Self` parameter, which in turn has a bound of the main trait,
|
||||||
|
@ -276,21 +265,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds));
|
obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds));
|
||||||
|
|
||||||
// Also add an obligation for the method type being well-formed.
|
// Also add an obligation for the method type being well-formed.
|
||||||
|
let method_ty = tcx.mk_fn_ptr(ty::Binder(fn_sig));
|
||||||
|
debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
|
||||||
|
method_ty,
|
||||||
|
obligation);
|
||||||
obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty)));
|
obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty)));
|
||||||
|
|
||||||
let autoref = match (&original_method_ty.fn_sig().input(0).skip_binder().sty,
|
|
||||||
&fn_sig.inputs()[0].sty) {
|
|
||||||
(&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => {
|
|
||||||
// Trait method is fn(&self) or fn(&mut self), need an
|
|
||||||
// autoref. Pull the region etc out of the type of first argument.
|
|
||||||
Some(AutoBorrow::Ref(region, mutbl))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// Trait method is fn(self), no transformation needed.
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let callee = MethodCallee {
|
let callee = MethodCallee {
|
||||||
def_id: def_id,
|
def_id: def_id,
|
||||||
substs: trait_ref.substs,
|
substs: trait_ref.substs,
|
||||||
|
@ -301,7 +281,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
Some(InferOk {
|
Some(InferOk {
|
||||||
obligations,
|
obligations,
|
||||||
value: (autoref, callee)
|
value: callee
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ use rustc::ty::subst::{Kind, Subst, Substs};
|
||||||
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal};
|
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal};
|
||||||
use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
|
use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
|
||||||
use rustc::ty::{self, Ty, TyCtxt, Visibility};
|
use rustc::ty::{self, Ty, TyCtxt, Visibility};
|
||||||
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
|
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||||
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
|
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
|
||||||
use rustc::ty::maps::Providers;
|
use rustc::ty::maps::Providers;
|
||||||
use rustc::ty::util::{Representability, IntTypeExt};
|
use rustc::ty::util::{Representability, IntTypeExt};
|
||||||
|
@ -1774,48 +1774,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_autoderef_adjustment(&self,
|
pub fn apply_adjustments(&self, expr: &hir::Expr, adj: Vec<Adjustment<'tcx>>) {
|
||||||
node_id: ast::NodeId,
|
debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
|
||||||
autoderefs: Vec<Option<OverloadedDeref<'tcx>>>,
|
|
||||||
adjusted_ty: Ty<'tcx>) {
|
|
||||||
self.apply_adjustment(node_id, Adjustment {
|
|
||||||
kind: Adjust::Deref(autoderefs),
|
|
||||||
autoref: None,
|
|
||||||
unsize: false,
|
|
||||||
target: adjusted_ty
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply_adjustment(&self, node_id: ast::NodeId, adj: Adjustment<'tcx>) {
|
if adj.is_empty() {
|
||||||
debug!("apply_adjustment(node_id={}, adj={:?})", node_id, adj);
|
|
||||||
|
|
||||||
if adj.is_identity() {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.tables.borrow_mut().adjustments.entry(node_id) {
|
match self.tables.borrow_mut().adjustments.entry(expr.id) {
|
||||||
Entry::Vacant(entry) => { entry.insert(adj); },
|
Entry::Vacant(entry) => { entry.insert(adj); },
|
||||||
Entry::Occupied(mut entry) => {
|
Entry::Occupied(mut entry) => {
|
||||||
debug!(" - composing on top of {:?}", entry.get());
|
debug!(" - composing on top of {:?}", entry.get());
|
||||||
match (entry.get(), &adj) {
|
match (&entry.get()[..], &adj[..]) {
|
||||||
// Applying any adjustment on top of a NeverToAny
|
// Applying any adjustment on top of a NeverToAny
|
||||||
// is a valid NeverToAny adjustment, because it can't
|
// is a valid NeverToAny adjustment, because it can't
|
||||||
// be reached.
|
// be reached.
|
||||||
(&Adjustment { kind: Adjust::NeverToAny, .. }, _) => return,
|
(&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return,
|
||||||
(&Adjustment {
|
(&[
|
||||||
kind: Adjust::Deref(ref old),
|
Adjustment { kind: Adjust::Deref(_), .. },
|
||||||
autoref: Some(AutoBorrow::Ref(..)),
|
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
|
||||||
unsize: false, ..
|
], &[
|
||||||
}, &Adjustment {
|
Adjustment { kind: Adjust::Deref(_), .. },
|
||||||
kind: Adjust::Deref(ref new), ..
|
.. // Any following adjustments are allowed.
|
||||||
}) if old.len() == 1 && new.len() >= 1 => {
|
]) => {
|
||||||
// A reborrow has no effect before a dereference.
|
// A reborrow has no effect before a dereference.
|
||||||
}
|
}
|
||||||
// FIXME: currently we never try to compose autoderefs
|
// FIXME: currently we never try to compose autoderefs
|
||||||
// and ReifyFnPointer/UnsafeFnPointer, but we could.
|
// and ReifyFnPointer/UnsafeFnPointer, but we could.
|
||||||
_ =>
|
_ =>
|
||||||
bug!("while adjusting {}, can't compose {:?} and {:?}",
|
bug!("while adjusting {:?}, can't compose {:?} and {:?}",
|
||||||
node_id, entry.get(), adj)
|
expr, entry.get(), adj)
|
||||||
};
|
};
|
||||||
*entry.get_mut() = adj;
|
*entry.get_mut() = adj;
|
||||||
}
|
}
|
||||||
|
@ -2189,7 +2177,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
index_ty: Ty<'tcx>)
|
index_ty: Ty<'tcx>)
|
||||||
-> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
|
-> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
|
||||||
{
|
{
|
||||||
let mut adjusted_ty = autoderef.unambiguous_final_ty();
|
let adjusted_ty = autoderef.unambiguous_final_ty();
|
||||||
debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
|
debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
|
||||||
index_ty={:?})",
|
index_ty={:?})",
|
||||||
expr,
|
expr,
|
||||||
|
@ -2202,19 +2190,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
match (adjusted_ty.builtin_index(), &index_ty.sty) {
|
match (adjusted_ty.builtin_index(), &index_ty.sty) {
|
||||||
(Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
|
(Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
|
||||||
debug!("try_index_step: success, using built-in indexing");
|
debug!("try_index_step: success, using built-in indexing");
|
||||||
let autoderefs = autoderef.adjust_steps(lvalue_pref);
|
let adjustments = autoderef.adjust_steps(lvalue_pref);
|
||||||
self.apply_autoderef_adjustment(
|
self.apply_adjustments(base_expr, adjustments);
|
||||||
base_expr.id, autoderefs, adjusted_ty);
|
|
||||||
return Some((self.tcx.types.usize, ty));
|
return Some((self.tcx.types.usize, ty));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
for &unsize in &[false, true] {
|
for &unsize in &[false, true] {
|
||||||
|
let mut self_ty = adjusted_ty;
|
||||||
if unsize {
|
if unsize {
|
||||||
// We only unsize arrays here.
|
// We only unsize arrays here.
|
||||||
if let ty::TyArray(element_ty, _) = adjusted_ty.sty {
|
if let ty::TyArray(element_ty, _) = adjusted_ty.sty {
|
||||||
adjusted_ty = self.tcx.mk_slice(element_ty);
|
self_ty = self.tcx.mk_slice(element_ty);
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2225,19 +2213,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// If some lookup succeeded, install method in table
|
// If some lookup succeeded, install method in table
|
||||||
let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span));
|
let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span));
|
||||||
let method = self.try_overloaded_lvalue_op(
|
let method = self.try_overloaded_lvalue_op(
|
||||||
expr.span, adjusted_ty, &[input_ty], lvalue_pref, LvalueOp::Index);
|
expr.span, self_ty, &[input_ty], lvalue_pref, LvalueOp::Index);
|
||||||
|
|
||||||
let result = method.map(|ok| {
|
let result = method.map(|ok| {
|
||||||
debug!("try_index_step: success, using overloaded indexing");
|
debug!("try_index_step: success, using overloaded indexing");
|
||||||
let (autoref, method) = self.register_infer_ok_obligations(ok);
|
let method = self.register_infer_ok_obligations(ok);
|
||||||
|
|
||||||
let autoderefs = autoderef.adjust_steps(lvalue_pref);
|
let mut adjustments = autoderef.adjust_steps(lvalue_pref);
|
||||||
self.apply_adjustment(base_expr.id, Adjustment {
|
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
|
||||||
kind: Adjust::Deref(autoderefs),
|
adjustments.push(Adjustment {
|
||||||
autoref,
|
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
|
||||||
unsize,
|
target: self.tcx.mk_ref(region, ty::TypeAndMut {
|
||||||
|
mutbl: mt.mutbl,
|
||||||
|
ty: adjusted_ty
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if unsize {
|
||||||
|
adjustments.push(Adjustment {
|
||||||
|
kind: Adjust::Unsize,
|
||||||
target: method.sig.inputs()[0]
|
target: method.sig.inputs()[0]
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
self.apply_adjustments(base_expr, adjustments);
|
||||||
|
|
||||||
self.write_method_call(expr.id, method);
|
self.write_method_call(expr.id, method);
|
||||||
(input_ty, self.make_overloaded_lvalue_return_type(method).ty)
|
(input_ty, self.make_overloaded_lvalue_return_type(method).ty)
|
||||||
|
@ -2270,9 +2268,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
arg_tys: &[Ty<'tcx>],
|
arg_tys: &[Ty<'tcx>],
|
||||||
lvalue_pref: LvaluePreference,
|
lvalue_pref: LvaluePreference,
|
||||||
op: LvalueOp)
|
op: LvalueOp)
|
||||||
-> Option<InferOk<'tcx,
|
-> Option<InferOk<'tcx, MethodCallee<'tcx>>>
|
||||||
(Option<AutoBorrow<'tcx>>,
|
|
||||||
MethodCallee<'tcx>)>>
|
|
||||||
{
|
{
|
||||||
debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?})",
|
debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?})",
|
||||||
span,
|
span,
|
||||||
|
@ -2284,11 +2280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let (mut_tr, mut_op) = self.resolve_lvalue_op(op, true);
|
let (mut_tr, mut_op) = self.resolve_lvalue_op(op, true);
|
||||||
let method = match (lvalue_pref, mut_tr) {
|
let method = match (lvalue_pref, mut_tr) {
|
||||||
(PreferMutLvalue, Some(trait_did)) => {
|
(PreferMutLvalue, Some(trait_did)) => {
|
||||||
self.lookup_method_in_trait_adjusted(span,
|
self.lookup_method_in_trait(span, mut_op, trait_did, base_ty, Some(arg_tys))
|
||||||
mut_op,
|
|
||||||
trait_did,
|
|
||||||
base_ty,
|
|
||||||
Some(arg_tys))
|
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
@ -2297,11 +2289,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let (imm_tr, imm_op) = self.resolve_lvalue_op(op, false);
|
let (imm_tr, imm_op) = self.resolve_lvalue_op(op, false);
|
||||||
let method = match (method, imm_tr) {
|
let method = match (method, imm_tr) {
|
||||||
(None, Some(trait_did)) => {
|
(None, Some(trait_did)) => {
|
||||||
self.lookup_method_in_trait_adjusted(span,
|
self.lookup_method_in_trait(span, imm_op, trait_did, base_ty, Some(arg_tys))
|
||||||
imm_op,
|
|
||||||
trait_did,
|
|
||||||
base_ty,
|
|
||||||
Some(arg_tys))
|
|
||||||
}
|
}
|
||||||
(method, _) => method,
|
(method, _) => method,
|
||||||
};
|
};
|
||||||
|
@ -2645,12 +2633,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
"expression with never type wound up being adjusted");
|
"expression with never type wound up being adjusted");
|
||||||
let adj_ty = self.next_diverging_ty_var(
|
let adj_ty = self.next_diverging_ty_var(
|
||||||
TypeVariableOrigin::AdjustmentType(expr.span));
|
TypeVariableOrigin::AdjustmentType(expr.span));
|
||||||
self.apply_adjustment(expr.id, Adjustment {
|
self.apply_adjustments(expr, vec![Adjustment {
|
||||||
kind: Adjust::NeverToAny,
|
kind: Adjust::NeverToAny,
|
||||||
autoref: None,
|
|
||||||
unsize: false,
|
|
||||||
target: adj_ty
|
target: adj_ty
|
||||||
});
|
}]);
|
||||||
ty = adj_ty;
|
ty = adj_ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2895,8 +2881,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) {
|
if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) {
|
||||||
let field_ty = self.field_ty(expr.span, field, substs);
|
let field_ty = self.field_ty(expr.span, field, substs);
|
||||||
if field.vis.is_accessible_from(def_scope, self.tcx) {
|
if field.vis.is_accessible_from(def_scope, self.tcx) {
|
||||||
let autoderefs = autoderef.adjust_steps(lvalue_pref);
|
let adjustments = autoderef.adjust_steps(lvalue_pref);
|
||||||
self.apply_autoderef_adjustment(base.id, autoderefs, base_t);
|
self.apply_adjustments(base, adjustments);
|
||||||
autoderef.finalize();
|
autoderef.finalize();
|
||||||
|
|
||||||
self.tcx.check_stability(field.did, expr.id, expr.span);
|
self.tcx.check_stability(field.did, expr.id, expr.span);
|
||||||
|
@ -3029,8 +3015,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(field_ty) = field {
|
if let Some(field_ty) = field {
|
||||||
let autoderefs = autoderef.adjust_steps(lvalue_pref);
|
let adjustments = autoderef.adjust_steps(lvalue_pref);
|
||||||
self.apply_autoderef_adjustment(base.id, autoderefs, base_t);
|
self.apply_adjustments(base, adjustments);
|
||||||
autoderef.finalize();
|
autoderef.finalize();
|
||||||
return field_ty;
|
return field_ty;
|
||||||
}
|
}
|
||||||
|
@ -3446,13 +3432,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
oprnd_t = mt.ty;
|
oprnd_t = mt.ty;
|
||||||
} else if let Some(ok) = self.try_overloaded_deref(
|
} else if let Some(ok) = self.try_overloaded_deref(
|
||||||
expr.span, oprnd_t, lvalue_pref) {
|
expr.span, oprnd_t, lvalue_pref) {
|
||||||
let (autoref, method) = self.register_infer_ok_obligations(ok);
|
let method = self.register_infer_ok_obligations(ok);
|
||||||
self.apply_adjustment(oprnd.id, Adjustment {
|
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
|
||||||
kind: Adjust::Deref(vec![]),
|
self.apply_adjustments(oprnd, vec![Adjustment {
|
||||||
autoref,
|
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
|
||||||
unsize: false,
|
|
||||||
target: method.sig.inputs()[0]
|
target: method.sig.inputs()[0]
|
||||||
});
|
}]);
|
||||||
|
}
|
||||||
oprnd_t = self.make_overloaded_lvalue_return_type(method).ty;
|
oprnd_t = self.make_overloaded_lvalue_return_type(method).ty;
|
||||||
self.write_method_call(expr.id, method);
|
self.write_method_call(expr.id, method);
|
||||||
} else {
|
} else {
|
||||||
|
@ -3466,9 +3452,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
hir::UnNot => {
|
hir::UnNot => {
|
||||||
oprnd_t = self.structurally_resolved_type(oprnd.span,
|
oprnd_t = self.structurally_resolved_type(oprnd.span,
|
||||||
oprnd_t);
|
oprnd_t);
|
||||||
let result = self.check_user_unop("!", "not",
|
let result = self.check_user_unop(expr, &oprnd, oprnd_t, unop);
|
||||||
tcx.lang_items.not_trait(),
|
|
||||||
expr, &oprnd, oprnd_t, unop);
|
|
||||||
// If it's builtin, we can reuse the type, this helps inference.
|
// If it's builtin, we can reuse the type, this helps inference.
|
||||||
if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) {
|
if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) {
|
||||||
oprnd_t = result;
|
oprnd_t = result;
|
||||||
|
@ -3477,9 +3461,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
hir::UnNeg => {
|
hir::UnNeg => {
|
||||||
oprnd_t = self.structurally_resolved_type(oprnd.span,
|
oprnd_t = self.structurally_resolved_type(oprnd.span,
|
||||||
oprnd_t);
|
oprnd_t);
|
||||||
let result = self.check_user_unop("-", "neg",
|
let result = self.check_user_unop(expr, &oprnd, oprnd_t, unop);
|
||||||
tcx.lang_items.neg_trait(),
|
|
||||||
expr, &oprnd, oprnd_t, unop);
|
|
||||||
// If it's builtin, we can reuse the type, this helps inference.
|
// If it's builtin, we can reuse the type, this helps inference.
|
||||||
if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
|
if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
|
||||||
oprnd_t = result;
|
oprnd_t = result;
|
||||||
|
|
|
@ -11,13 +11,11 @@
|
||||||
//! Code related to processing overloaded binary and unary operators.
|
//! Code related to processing overloaded binary and unary operators.
|
||||||
|
|
||||||
use super::FnCtxt;
|
use super::FnCtxt;
|
||||||
use hir::def_id::DefId;
|
use rustc::ty::{self, Ty, TypeFoldable, PreferMutLvalue, TypeVariants};
|
||||||
use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants};
|
|
||||||
use rustc::ty::TypeVariants::{TyStr, TyRef};
|
use rustc::ty::TypeVariants::{TyStr, TyRef};
|
||||||
use rustc::ty::adjustment::{Adjustment, Adjust};
|
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
||||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||||
use errors;
|
use errors;
|
||||||
use syntax::ast;
|
|
||||||
use syntax::symbol::Symbol;
|
use syntax::symbol::Symbol;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
|
||||||
|
@ -175,8 +173,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
lhs_ty,
|
lhs_ty,
|
||||||
is_assign);
|
is_assign);
|
||||||
|
|
||||||
let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign);
|
|
||||||
|
|
||||||
// NB: As we have not yet type-checked the RHS, we don't have the
|
// NB: As we have not yet type-checked the RHS, we don't have the
|
||||||
// type at hand. Make a variable to represent it. The whole reason
|
// type at hand. Make a variable to represent it. The whole reason
|
||||||
// for this indirection is so that, below, we can check the expr
|
// for this indirection is so that, below, we can check the expr
|
||||||
|
@ -186,8 +182,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span));
|
let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span));
|
||||||
|
|
||||||
let return_ty = self.lookup_op_method(expr, lhs_ty, &[rhs_ty_var],
|
let return_ty = self.lookup_op_method(expr, lhs_ty, &[rhs_ty_var],
|
||||||
Symbol::intern(name), trait_def_id,
|
Op::Binary(op, is_assign), lhs_expr);
|
||||||
lhs_expr);
|
|
||||||
|
|
||||||
// see `NB` above
|
// see `NB` above
|
||||||
let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
|
let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
|
||||||
|
@ -216,8 +211,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty {
|
if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty {
|
||||||
if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) &&
|
if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) &&
|
||||||
self.lookup_op_method(expr, ty_mut.ty, &[rhs_ty],
|
self.lookup_op_method(expr, ty_mut.ty, &[rhs_ty],
|
||||||
Symbol::intern(name), trait_def_id,
|
Op::Binary(op, is_assign), lhs_expr).is_ok() {
|
||||||
lhs_expr).is_ok() {
|
|
||||||
err.note(
|
err.note(
|
||||||
&format!(
|
&format!(
|
||||||
"this is a reference to a type that `{}` can be applied \
|
"this is a reference to a type that `{}` can be applied \
|
||||||
|
@ -303,9 +297,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_user_unop(&self,
|
pub fn check_user_unop(&self,
|
||||||
op_str: &str,
|
|
||||||
mname: &str,
|
|
||||||
trait_did: Option<DefId>,
|
|
||||||
ex: &'gcx hir::Expr,
|
ex: &'gcx hir::Expr,
|
||||||
operand_expr: &'gcx hir::Expr,
|
operand_expr: &'gcx hir::Expr,
|
||||||
operand_ty: Ty<'tcx>,
|
operand_ty: Ty<'tcx>,
|
||||||
|
@ -313,28 +304,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
-> Ty<'tcx>
|
-> Ty<'tcx>
|
||||||
{
|
{
|
||||||
assert!(op.is_by_value());
|
assert!(op.is_by_value());
|
||||||
let mname = Symbol::intern(mname);
|
match self.lookup_op_method(ex, operand_ty, &[], Op::Unary(op), operand_expr) {
|
||||||
match self.lookup_op_method(ex, operand_ty, &[], mname, trait_did, operand_expr) {
|
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
let actual = self.resolve_type_vars_if_possible(&operand_ty);
|
let actual = self.resolve_type_vars_if_possible(&operand_ty);
|
||||||
if !actual.references_error() {
|
if !actual.references_error() {
|
||||||
struct_span_err!(self.tcx.sess, ex.span, E0600,
|
struct_span_err!(self.tcx.sess, ex.span, E0600,
|
||||||
"cannot apply unary operator `{}` to type `{}`",
|
"cannot apply unary operator `{}` to type `{}`",
|
||||||
op_str, actual).emit();
|
op.as_str(), actual).emit();
|
||||||
}
|
}
|
||||||
self.tcx.types.err
|
self.tcx.types.err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name_and_trait_def_id(&self,
|
fn lookup_op_method(&self,
|
||||||
op: hir::BinOp,
|
expr: &'gcx hir::Expr,
|
||||||
is_assign: IsAssign)
|
lhs_ty: Ty<'tcx>,
|
||||||
-> (&'static str, Option<DefId>) {
|
other_tys: &[Ty<'tcx>],
|
||||||
|
op: Op,
|
||||||
|
lhs_expr: &'a hir::Expr)
|
||||||
|
-> Result<Ty<'tcx>,()>
|
||||||
|
{
|
||||||
let lang = &self.tcx.lang_items;
|
let lang = &self.tcx.lang_items;
|
||||||
|
|
||||||
if let IsAssign::Yes = is_assign {
|
let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op {
|
||||||
match op.node {
|
match op.node {
|
||||||
hir::BiAdd => ("add_assign", lang.add_assign_trait()),
|
hir::BiAdd => ("add_assign", lang.add_assign_trait()),
|
||||||
hir::BiSub => ("sub_assign", lang.sub_assign_trait()),
|
hir::BiSub => ("sub_assign", lang.sub_assign_trait()),
|
||||||
|
@ -355,7 +349,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
op.node.as_str())
|
op.node.as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if let Op::Binary(op, IsAssign::No) = op {
|
||||||
match op.node {
|
match op.node {
|
||||||
hir::BiAdd => ("add", lang.add_trait()),
|
hir::BiAdd => ("add", lang.add_trait()),
|
||||||
hir::BiSub => ("sub", lang.sub_trait()),
|
hir::BiSub => ("sub", lang.sub_trait()),
|
||||||
|
@ -377,18 +371,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
span_bug!(op.span, "&& and || are not overloadable")
|
span_bug!(op.span, "&& and || are not overloadable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if let Op::Unary(hir::UnNot) = op {
|
||||||
}
|
("not", lang.not_trait())
|
||||||
|
} else if let Op::Unary(hir::UnNeg) = op {
|
||||||
|
("neg", lang.neg_trait())
|
||||||
|
} else {
|
||||||
|
bug!("lookup_op_method: op not supported: {:?}", op)
|
||||||
|
};
|
||||||
|
|
||||||
fn lookup_op_method(&self,
|
|
||||||
expr: &'gcx hir::Expr,
|
|
||||||
lhs_ty: Ty<'tcx>,
|
|
||||||
other_tys: &[Ty<'tcx>],
|
|
||||||
opname: ast::Name,
|
|
||||||
trait_did: Option<DefId>,
|
|
||||||
lhs_expr: &'a hir::Expr)
|
|
||||||
-> Result<Ty<'tcx>,()>
|
|
||||||
{
|
|
||||||
debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, \
|
debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, \
|
||||||
trait_did={:?}, lhs_expr={:?})",
|
trait_did={:?}, lhs_expr={:?})",
|
||||||
expr,
|
expr,
|
||||||
|
@ -397,28 +387,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
trait_did,
|
trait_did,
|
||||||
lhs_expr);
|
lhs_expr);
|
||||||
|
|
||||||
let method = match trait_did {
|
let method = trait_did.and_then(|trait_did| {
|
||||||
Some(trait_did) => {
|
let opname = Symbol::intern(opname);
|
||||||
self.lookup_method_in_trait_adjusted(expr.span,
|
self.lookup_method_in_trait(expr.span, opname, trait_did, lhs_ty, Some(other_tys))
|
||||||
opname,
|
});
|
||||||
trait_did,
|
|
||||||
lhs_ty,
|
|
||||||
Some(other_tys))
|
|
||||||
}
|
|
||||||
None => None
|
|
||||||
};
|
|
||||||
|
|
||||||
match method {
|
match method {
|
||||||
Some(ok) => {
|
Some(ok) => {
|
||||||
let (autoref, method) = self.register_infer_ok_obligations(ok);
|
let method = self.register_infer_ok_obligations(ok);
|
||||||
self.select_obligations_where_possible();
|
self.select_obligations_where_possible();
|
||||||
|
|
||||||
self.apply_adjustment(lhs_expr.id, Adjustment {
|
let (lhs_by_ref, _rhs_by_ref) = match op {
|
||||||
kind: Adjust::Deref(vec![]),
|
Op::Binary(_, IsAssign::Yes) => (true, false),
|
||||||
autoref,
|
Op::Binary(op, _) if !op.node.is_by_value() => (true, true),
|
||||||
unsize: false,
|
Op::Binary(..) | Op::Unary(_) => (false, false),
|
||||||
|
};
|
||||||
|
if lhs_by_ref {
|
||||||
|
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
|
||||||
|
let autoref = Adjustment {
|
||||||
|
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
|
||||||
target: method.sig.inputs()[0]
|
target: method.sig.inputs()[0]
|
||||||
});
|
};
|
||||||
|
self.apply_adjustments(lhs_expr, vec![autoref]);
|
||||||
|
}
|
||||||
|
}
|
||||||
self.write_method_call(expr.id, method);
|
self.write_method_call(expr.id, method);
|
||||||
|
|
||||||
Ok(method.sig.output())
|
Ok(method.sig.output())
|
||||||
|
@ -493,6 +485,12 @@ enum IsAssign {
|
||||||
Yes,
|
Yes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum Op {
|
||||||
|
Binary(hir::BinOp, IsAssign),
|
||||||
|
Unary(hir::UnOp),
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if this is a built-in arithmetic operation (e.g. u32
|
/// Returns true if this is a built-in arithmetic operation (e.g. u32
|
||||||
/// + u32, i16x4 == i16x4) and false if these types would have to be
|
/// + u32, i16x4 == i16x4) and false if these types would have to be
|
||||||
/// overloaded to be legal. There are two reasons that we distinguish
|
/// overloaded to be legal. There are two reasons that we distinguish
|
||||||
|
|
|
@ -542,61 +542,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check any autoderefs or autorefs that appear.
|
// Check any autoderefs or autorefs that appear.
|
||||||
let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
|
let cmt_result = self.constrain_adjustments(expr);
|
||||||
if let Some(adjustment) = adjustment {
|
|
||||||
debug!("adjustment={:?}", adjustment);
|
|
||||||
match adjustment.kind {
|
|
||||||
adjustment::Adjust::Deref(ref autoderefs) => {
|
|
||||||
let cmt = ignore_err!(self.constrain_autoderefs(expr, autoderefs));
|
|
||||||
if let Some(ref autoref) = adjustment.autoref {
|
|
||||||
self.link_autoref(expr, cmt, autoref);
|
|
||||||
|
|
||||||
// Require that the resulting region encompasses
|
|
||||||
// the current node.
|
|
||||||
//
|
|
||||||
// FIXME(#6268) remove to support nested method calls
|
|
||||||
self.type_of_node_must_outlive(infer::AutoBorrow(expr.span),
|
|
||||||
expr.id, expr_region);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
adjustment::AutoObject(_, ref bounds, ..) => {
|
|
||||||
// Determine if we are casting `expr` to a trait
|
|
||||||
// instance. If so, we have to be sure that the type
|
|
||||||
// of the source obeys the new region bound.
|
|
||||||
let source_ty = self.resolve_node_type(expr.id);
|
|
||||||
self.type_must_outlive(infer::RelateObjectBound(expr.span),
|
|
||||||
source_ty, bounds.region_bound);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
_ => {
|
|
||||||
assert!(adjustment.autoref.is_none());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If necessary, constrain destructors in the unadjusted form of this
|
|
||||||
// expression.
|
|
||||||
let cmt_result = {
|
|
||||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
|
||||||
mc.cat_expr_unadjusted(expr)
|
|
||||||
};
|
|
||||||
match cmt_result {
|
|
||||||
Ok(head_cmt) => {
|
|
||||||
self.check_safety_of_rvalue_destructor_if_necessary(head_cmt,
|
|
||||||
expr.span);
|
|
||||||
}
|
|
||||||
Err(..) => {
|
|
||||||
self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If necessary, constrain destructors in this expression. This will be
|
// If necessary, constrain destructors in this expression. This will be
|
||||||
// the adjusted form if there is an adjustment.
|
// the adjusted form if there is an adjustment.
|
||||||
let cmt_result = {
|
|
||||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
|
||||||
mc.cat_expr(expr)
|
|
||||||
};
|
|
||||||
match cmt_result {
|
match cmt_result {
|
||||||
Ok(head_cmt) => {
|
Ok(head_cmt) => {
|
||||||
self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span);
|
self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span);
|
||||||
|
@ -904,26 +853,35 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked on any auto-dereference that occurs. Checks that if this is a region pointer being
|
/// Invoked on any adjustments that occur. Checks that if this is a region pointer being
|
||||||
/// dereferenced, the lifetime of the pointer includes the deref expr.
|
/// dereferenced, the lifetime of the pointer includes the deref expr.
|
||||||
fn constrain_autoderefs(&mut self,
|
fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult<mc::cmt<'tcx>> {
|
||||||
deref_expr: &hir::Expr,
|
debug!("constrain_adjustments(expr={:?})", expr);
|
||||||
autoderefs: &[Option<adjustment::OverloadedDeref<'tcx>>])
|
|
||||||
-> mc::McResult<mc::cmt<'tcx>>
|
|
||||||
{
|
|
||||||
debug!("constrain_autoderefs(deref_expr={:?}, autoderefs={:?})",
|
|
||||||
deref_expr,
|
|
||||||
autoderefs);
|
|
||||||
|
|
||||||
let mut cmt = {
|
let mut cmt = {
|
||||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
||||||
mc.cat_expr_unadjusted(deref_expr)?
|
mc.cat_expr_unadjusted(expr)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let r_deref_expr = self.tcx.node_scope_region(deref_expr.id);
|
//NOTE(@jroesch): mixed RefCell borrow causes crash
|
||||||
for &overloaded in autoderefs {
|
let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec();
|
||||||
if let Some(deref) = overloaded {
|
if adjustments.is_empty() {
|
||||||
debug!("constrain_autoderefs: overloaded, {:?}", deref);
|
return Ok(cmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("constrain_adjustments: adjustments={:?}", adjustments);
|
||||||
|
|
||||||
|
// If necessary, constrain destructors in the unadjusted form of this
|
||||||
|
// expression.
|
||||||
|
self.check_safety_of_rvalue_destructor_if_necessary(cmt.clone(), expr.span);
|
||||||
|
|
||||||
|
let expr_region = self.tcx.node_scope_region(expr.id);
|
||||||
|
for adjustment in adjustments {
|
||||||
|
debug!("constrain_adjustments: adjustment={:?}, cmt={:?}",
|
||||||
|
adjustment, cmt);
|
||||||
|
|
||||||
|
if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind {
|
||||||
|
debug!("constrain_adjustments: overloaded deref: {:?}", deref);
|
||||||
|
|
||||||
// Treat overloaded autoderefs as if an AutoBorrow adjustment
|
// Treat overloaded autoderefs as if an AutoBorrow adjustment
|
||||||
// was applied on the base type, as that is always the case.
|
// was applied on the base type, as that is always the case.
|
||||||
|
@ -932,33 +890,39 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||||
mutbl: deref.mutbl,
|
mutbl: deref.mutbl,
|
||||||
});
|
});
|
||||||
let output = self.tcx.mk_ref(deref.region, ty::TypeAndMut {
|
let output = self.tcx.mk_ref(deref.region, ty::TypeAndMut {
|
||||||
ty: deref.target,
|
ty: adjustment.target,
|
||||||
mutbl: deref.mutbl,
|
mutbl: deref.mutbl,
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!("constrain_autoderefs: self_cmt={:?}", cmt);
|
self.link_region(expr.span, deref.region,
|
||||||
self.link_region(deref_expr.span, deref.region,
|
|
||||||
ty::BorrowKind::from_mutbl(deref.mutbl), cmt.clone());
|
ty::BorrowKind::from_mutbl(deref.mutbl), cmt.clone());
|
||||||
|
|
||||||
// Specialized version of constrain_call.
|
// Specialized version of constrain_call.
|
||||||
self.type_must_outlive(infer::CallRcvr(deref_expr.span),
|
self.type_must_outlive(infer::CallRcvr(expr.span),
|
||||||
input, r_deref_expr);
|
input, expr_region);
|
||||||
self.type_must_outlive(infer::CallReturn(deref_expr.span),
|
self.type_must_outlive(infer::CallReturn(expr.span),
|
||||||
output, r_deref_expr);
|
output, expr_region);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind {
|
||||||
|
self.link_autoref(expr, cmt.clone(), autoref);
|
||||||
|
|
||||||
|
// Require that the resulting region encompasses
|
||||||
|
// the current node.
|
||||||
|
//
|
||||||
|
// FIXME(#6268) remove to support nested method calls
|
||||||
|
self.type_of_node_must_outlive(infer::AutoBorrow(expr.span),
|
||||||
|
expr.id, expr_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
|
||||||
if let Some(deref) = overloaded {
|
cmt = mc.cat_expr_adjusted(expr, cmt, &adjustment)?;
|
||||||
cmt = mc.cat_overloaded_autoderef(deref_expr, deref)?;
|
|
||||||
} else {
|
|
||||||
cmt = mc.cat_deref(deref_expr, cmt, false)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat {
|
if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat {
|
||||||
self.mk_subregion_due_to_dereference(deref_expr.span,
|
self.mk_subregion_due_to_dereference(expr.span,
|
||||||
r_deref_expr, r_ptr);
|
expr_region, r_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,7 +993,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||||
// is going to fail anyway, so just stop here and let typeck
|
// is going to fail anyway, so just stop here and let typeck
|
||||||
// report errors later on in the writeback phase.
|
// report errors later on in the writeback phase.
|
||||||
let ty0 = self.resolve_node_type(id);
|
let ty0 = self.resolve_node_type(id);
|
||||||
let ty = self.tables.borrow().adjustments.get(&id).map_or(ty0, |adj| adj.target);
|
let ty = self.tables.borrow().adjustments.get(&id)
|
||||||
|
.and_then(|adj| adj.last())
|
||||||
|
.map_or(ty0, |adj| adj.target);
|
||||||
let ty = self.resolve_type(ty);
|
let ty = self.resolve_type(ty);
|
||||||
debug!("constrain_regions_in_type_of_node(\
|
debug!("constrain_regions_in_type_of_node(\
|
||||||
ty={}, ty0={}, id={}, minimum_lifetime={:?})",
|
ty={}, ty0={}, id={}, minimum_lifetime={:?})",
|
||||||
|
|
|
@ -73,12 +73,14 @@ This API is completely unstable and subject to change.
|
||||||
|
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
|
#![feature(advanced_slice_patterns)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(conservative_impl_trait)]
|
#![feature(conservative_impl_trait)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(quote)]
|
#![feature(quote)]
|
||||||
#![feature(rustc_diagnostic_macros)]
|
#![feature(rustc_diagnostic_macros)]
|
||||||
|
#![feature(slice_patterns)]
|
||||||
|
|
||||||
#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
|
#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
|
||||||
#![cfg_attr(stage0, feature(rustc_private))]
|
#![cfg_attr(stage0, feature(rustc_private))]
|
||||||
|
|
Loading…
Reference in New Issue