mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 03:38:29 +00:00
librustc: Improve method autoderef/deref/index behavior more, and enable
`IndexMut` on mutable vectors. This fixes a bug whereby the mutability fixups for method behavior were not kicking in after autoderef failed to happen at any level. It also adds support for `Index` to the fixer-upper. Closes #12825.
This commit is contained in:
parent
dfd52817ee
commit
f7fb38729e
@ -452,13 +452,13 @@ impl<T> Index<uint,T> for Vec<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(#12825) Indexing will always try IndexMut first and that causes issues.
|
#[cfg(not(stage0))]
|
||||||
/*impl<T> IndexMut<uint,T> for Vec<T> {
|
impl<T> IndexMut<uint,T> for Vec<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut T {
|
fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut T {
|
||||||
self.get_mut(*index)
|
self.get_mut(*index)
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
impl<T> ops::Slice<uint, [T]> for Vec<T> {
|
impl<T> ops::Slice<uint, [T]> for Vec<T> {
|
||||||
@ -2191,7 +2191,6 @@ impl<T> Vec<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
@ -359,8 +359,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
|
|||||||
|
|
||||||
match result {
|
match result {
|
||||||
Some(Some(result)) => {
|
Some(Some(result)) => {
|
||||||
self.fixup_derefs_on_method_receiver_if_necessary(&result,
|
self.fixup_derefs_on_method_receiver_if_necessary(&result);
|
||||||
self_ty);
|
|
||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None
|
||||||
@ -1388,8 +1387,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
|
|||||||
|
|
||||||
fn fixup_derefs_on_method_receiver_if_necessary(
|
fn fixup_derefs_on_method_receiver_if_necessary(
|
||||||
&self,
|
&self,
|
||||||
method_callee: &MethodCallee,
|
method_callee: &MethodCallee) {
|
||||||
self_ty: ty::t) {
|
|
||||||
let sig = match ty::get(method_callee.ty).sty {
|
let sig = match ty::get(method_callee.ty).sty {
|
||||||
ty::ty_bare_fn(ref f) => f.sig.clone(),
|
ty::ty_bare_fn(ref f) => f.sig.clone(),
|
||||||
ty::ty_closure(ref f) => f.sig.clone(),
|
ty::ty_closure(ref f) => f.sig.clone(),
|
||||||
@ -1404,55 +1402,82 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
|
|||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix up autoderefs and derefs.
|
// Gather up expressions we want to munge.
|
||||||
let mut self_expr = match self.self_expr {
|
let mut exprs = Vec::new();
|
||||||
Some(expr) => expr,
|
match self.self_expr {
|
||||||
None => return,
|
Some(expr) => exprs.push(expr),
|
||||||
};
|
None => {}
|
||||||
|
}
|
||||||
loop {
|
loop {
|
||||||
|
if exprs.len() == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
let last = exprs[exprs.len() - 1];
|
||||||
|
match last.node {
|
||||||
|
ast::ExprParen(ref expr) |
|
||||||
|
ast::ExprField(ref expr, _, _) |
|
||||||
|
ast::ExprTupField(ref expr, _, _) |
|
||||||
|
ast::ExprSlice(ref expr, _, _, _) |
|
||||||
|
ast::ExprIndex(ref expr, _) |
|
||||||
|
ast::ExprUnary(ast::UnDeref, ref expr) => exprs.push(&**expr),
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix up autoderefs and derefs.
|
||||||
|
for (i, expr) in exprs.iter().rev().enumerate() {
|
||||||
// Count autoderefs.
|
// Count autoderefs.
|
||||||
let autoderef_count = match self.fcx
|
let autoderef_count = match self.fcx
|
||||||
.inh
|
.inh
|
||||||
.adjustments
|
.adjustments
|
||||||
.borrow()
|
.borrow()
|
||||||
.find(&self_expr.id) {
|
.find(&expr.id) {
|
||||||
Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
|
Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
|
||||||
autoderefs: autoderef_count,
|
autoderefs: autoderef_count,
|
||||||
autoref: _
|
autoref: _
|
||||||
})) if autoderef_count > 0 => autoderef_count,
|
})) => autoderef_count,
|
||||||
Some(_) | None => return,
|
Some(_) | None => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
check::autoderef(self.fcx,
|
if autoderef_count > 0 {
|
||||||
self_expr.span,
|
check::autoderef(self.fcx,
|
||||||
self.fcx.expr_ty(self_expr),
|
expr.span,
|
||||||
Some(self_expr.id),
|
self.fcx.expr_ty(*expr),
|
||||||
PreferMutLvalue,
|
Some(expr.id),
|
||||||
|_, autoderefs| {
|
PreferMutLvalue,
|
||||||
if autoderefs == autoderef_count + 1 {
|
|_, autoderefs| {
|
||||||
Some(())
|
if autoderefs == autoderef_count + 1 {
|
||||||
} else {
|
Some(())
|
||||||
None
|
} else {
|
||||||
}
|
None
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
match self_expr.node {
|
// Don't retry the first one or we might infinite loop!
|
||||||
ast::ExprParen(ref expr) |
|
if i != 0 {
|
||||||
ast::ExprIndex(ref expr, _) |
|
match expr.node {
|
||||||
ast::ExprField(ref expr, _, _) |
|
ast::ExprIndex(ref base_expr, ref index_expr) => {
|
||||||
ast::ExprTupField(ref expr, _, _) |
|
check::try_overloaded_index(
|
||||||
ast::ExprSlice(ref expr, _, _, _) => self_expr = &**expr,
|
self.fcx,
|
||||||
ast::ExprUnary(ast::UnDeref, ref expr) => {
|
Some(MethodCall::expr(expr.id)),
|
||||||
drop(check::try_overloaded_deref(
|
*expr,
|
||||||
self.fcx,
|
&**base_expr,
|
||||||
self_expr.span,
|
self.fcx.expr_ty(&**base_expr),
|
||||||
Some(MethodCall::expr(self_expr.id)),
|
index_expr,
|
||||||
Some(self_expr),
|
PreferMutLvalue);
|
||||||
self_ty,
|
}
|
||||||
PreferMutLvalue));
|
ast::ExprUnary(ast::UnDeref, ref base_expr) => {
|
||||||
self_expr = &**expr
|
check::try_overloaded_deref(
|
||||||
|
self.fcx,
|
||||||
|
expr.span,
|
||||||
|
Some(MethodCall::expr(expr.id)),
|
||||||
|
Some(&**base_expr),
|
||||||
|
self.fcx.expr_ty(&**base_expr),
|
||||||
|
PreferMutLvalue);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
_ => break,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2975,12 +2975,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
|||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
method_name: ast::SpannedIdent,
|
method_name: ast::SpannedIdent,
|
||||||
args: &[P<ast::Expr>],
|
args: &[P<ast::Expr>],
|
||||||
tps: &[P<ast::Ty>]) {
|
tps: &[P<ast::Ty>],
|
||||||
|
lvalue_pref: LvaluePreference) {
|
||||||
let rcvr = &*args[0];
|
let rcvr = &*args[0];
|
||||||
// We can't know if we need &mut self before we look up the method,
|
check_expr_with_lvalue_pref(fcx, &*rcvr, lvalue_pref);
|
||||||
// so treat the receiver as mutable just in case - only explicit
|
|
||||||
// overloaded dereferences care about the distinction.
|
|
||||||
check_expr_with_lvalue_pref(fcx, &*rcvr, PreferMutLvalue);
|
|
||||||
|
|
||||||
// no need to check for bot/err -- callee does that
|
// no need to check for bot/err -- callee does that
|
||||||
let expr_t = structurally_resolved_type(fcx,
|
let expr_t = structurally_resolved_type(fcx,
|
||||||
@ -4195,7 +4193,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprMethodCall(ident, ref tps, ref args) => {
|
ast::ExprMethodCall(ident, ref tps, ref args) => {
|
||||||
check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice());
|
check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice(), lvalue_pref);
|
||||||
let mut arg_tys = args.iter().map(|a| fcx.expr_ty(&**a));
|
let mut arg_tys = args.iter().map(|a| fcx.expr_ty(&**a));
|
||||||
let (args_bot, args_err) = arg_tys.fold((false, false),
|
let (args_bot, args_err) = arg_tys.fold((false, false),
|
||||||
|(rest_bot, rest_err), a| {
|
|(rest_bot, rest_err), a| {
|
||||||
|
@ -68,12 +68,10 @@ pub fn main() {
|
|||||||
*n -= 3; // Mutable deref + assignment with binary operation.
|
*n -= 3; // Mutable deref + assignment with binary operation.
|
||||||
assert_eq!(n.counts(), (2, 3));
|
assert_eq!(n.counts(), (2, 3));
|
||||||
|
|
||||||
// Mutable deref used for calling a method taking &self.
|
// Immutable deref used for calling a method taking &self. (The
|
||||||
// N.B. This is required because method lookup hasn't been performed so
|
// typechecker is smarter now about doing this.)
|
||||||
// we don't know whether the called method takes mutable self, before
|
|
||||||
// the dereference itself is type-checked (a chicken-and-egg problem).
|
|
||||||
(*n).to_string();
|
(*n).to_string();
|
||||||
assert_eq!(n.counts(), (2, 4));
|
assert_eq!(n.counts(), (3, 3));
|
||||||
|
|
||||||
// Mutable deref used for calling a method taking &mut self.
|
// Mutable deref used for calling a method taking &mut self.
|
||||||
(*v).push(2);
|
(*v).push(2);
|
||||||
|
Loading…
Reference in New Issue
Block a user