Skip to content

Commit 8096fee

Browse files
committed
auto merge of #17934 : pcwalton/rust/better-autoderef-fixup, r=pnkfelix
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. r? @pnkfelix
2 parents 7134fc8 + f7fb387 commit 8096fee

File tree

4 files changed

+76
-56
lines changed

4 files changed

+76
-56
lines changed

src/libcollections/vec.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -453,13 +453,13 @@ impl<T> Index<uint,T> for Vec<T> {
453453
}
454454
}
455455

456-
// FIXME(#12825) Indexing will always try IndexMut first and that causes issues.
457-
/*impl<T> IndexMut<uint,T> for Vec<T> {
456+
#[cfg(not(stage0))]
457+
impl<T> IndexMut<uint,T> for Vec<T> {
458458
#[inline]
459459
fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut T {
460460
self.get_mut(*index)
461461
}
462-
}*/
462+
}
463463

464464
impl<T> ops::Slice<uint, [T]> for Vec<T> {
465465
#[inline]
@@ -2154,7 +2154,6 @@ impl<T> Vec<T> {
21542154
}
21552155
}
21562156

2157-
21582157
#[cfg(test)]
21592158
mod tests {
21602159
extern crate test;

src/librustc/middle/typeck/check/method.rs

+66-41
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
359359

360360
match result {
361361
Some(Some(result)) => {
362-
self.fixup_derefs_on_method_receiver_if_necessary(&result,
363-
self_ty);
362+
self.fixup_derefs_on_method_receiver_if_necessary(&result);
364363
Some(result)
365364
}
366365
_ => None
@@ -1388,8 +1387,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
13881387

13891388
fn fixup_derefs_on_method_receiver_if_necessary(
13901389
&self,
1391-
method_callee: &MethodCallee,
1392-
self_ty: ty::t) {
1390+
method_callee: &MethodCallee) {
13931391
let sig = match ty::get(method_callee.ty).sty {
13941392
ty::ty_bare_fn(ref f) => f.sig.clone(),
13951393
ty::ty_closure(ref f) => f.sig.clone(),
@@ -1404,55 +1402,82 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
14041402
_ => return,
14051403
}
14061404

1407-
// Fix up autoderefs and derefs.
1408-
let mut self_expr = match self.self_expr {
1409-
Some(expr) => expr,
1410-
None => return,
1411-
};
1405+
// Gather up expressions we want to munge.
1406+
let mut exprs = Vec::new();
1407+
match self.self_expr {
1408+
Some(expr) => exprs.push(expr),
1409+
None => {}
1410+
}
14121411
loop {
1412+
if exprs.len() == 0 {
1413+
break
1414+
}
1415+
let last = exprs[exprs.len() - 1];
1416+
match last.node {
1417+
ast::ExprParen(ref expr) |
1418+
ast::ExprField(ref expr, _, _) |
1419+
ast::ExprTupField(ref expr, _, _) |
1420+
ast::ExprSlice(ref expr, _, _, _) |
1421+
ast::ExprIndex(ref expr, _) |
1422+
ast::ExprUnary(ast::UnDeref, ref expr) => exprs.push(&**expr),
1423+
_ => break,
1424+
}
1425+
}
1426+
1427+
// Fix up autoderefs and derefs.
1428+
for (i, expr) in exprs.iter().rev().enumerate() {
14131429
// Count autoderefs.
14141430
let autoderef_count = match self.fcx
14151431
.inh
14161432
.adjustments
14171433
.borrow()
1418-
.find(&self_expr.id) {
1434+
.find(&expr.id) {
14191435
Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
14201436
autoderefs: autoderef_count,
14211437
autoref: _
1422-
})) if autoderef_count > 0 => autoderef_count,
1423-
Some(_) | None => return,
1438+
})) => autoderef_count,
1439+
Some(_) | None => 0,
14241440
};
14251441

1426-
check::autoderef(self.fcx,
1427-
self_expr.span,
1428-
self.fcx.expr_ty(self_expr),
1429-
Some(self_expr.id),
1430-
PreferMutLvalue,
1431-
|_, autoderefs| {
1432-
if autoderefs == autoderef_count + 1 {
1433-
Some(())
1434-
} else {
1435-
None
1436-
}
1437-
});
1438-
1439-
match self_expr.node {
1440-
ast::ExprParen(ref expr) |
1441-
ast::ExprIndex(ref expr, _) |
1442-
ast::ExprField(ref expr, _, _) |
1443-
ast::ExprTupField(ref expr, _, _) |
1444-
ast::ExprSlice(ref expr, _, _, _) => self_expr = &**expr,
1445-
ast::ExprUnary(ast::UnDeref, ref expr) => {
1446-
drop(check::try_overloaded_deref(
1447-
self.fcx,
1448-
self_expr.span,
1449-
Some(MethodCall::expr(self_expr.id)),
1450-
Some(self_expr),
1451-
self_ty,
1452-
PreferMutLvalue));
1453-
self_expr = &**expr
1442+
if autoderef_count > 0 {
1443+
check::autoderef(self.fcx,
1444+
expr.span,
1445+
self.fcx.expr_ty(*expr),
1446+
Some(expr.id),
1447+
PreferMutLvalue,
1448+
|_, autoderefs| {
1449+
if autoderefs == autoderef_count + 1 {
1450+
Some(())
1451+
} else {
1452+
None
1453+
}
1454+
});
1455+
}
1456+
1457+
// Don't retry the first one or we might infinite loop!
1458+
if i != 0 {
1459+
match expr.node {
1460+
ast::ExprIndex(ref base_expr, ref index_expr) => {
1461+
check::try_overloaded_index(
1462+
self.fcx,
1463+
Some(MethodCall::expr(expr.id)),
1464+
*expr,
1465+
&**base_expr,
1466+
self.fcx.expr_ty(&**base_expr),
1467+
index_expr,
1468+
PreferMutLvalue);
1469+
}
1470+
ast::ExprUnary(ast::UnDeref, ref base_expr) => {
1471+
check::try_overloaded_deref(
1472+
self.fcx,
1473+
expr.span,
1474+
Some(MethodCall::expr(expr.id)),
1475+
Some(&**base_expr),
1476+
self.fcx.expr_ty(&**base_expr),
1477+
PreferMutLvalue);
1478+
}
1479+
_ => {}
14541480
}
1455-
_ => break,
14561481
}
14571482
}
14581483
}

src/librustc/middle/typeck/check/mod.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -2918,12 +2918,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
29182918
expr: &ast::Expr,
29192919
method_name: ast::SpannedIdent,
29202920
args: &[P<ast::Expr>],
2921-
tps: &[P<ast::Ty>]) {
2921+
tps: &[P<ast::Ty>],
2922+
lvalue_pref: LvaluePreference) {
29222923
let rcvr = &*args[0];
2923-
// We can't know if we need &mut self before we look up the method,
2924-
// so treat the receiver as mutable just in case - only explicit
2925-
// overloaded dereferences care about the distinction.
2926-
check_expr_with_lvalue_pref(fcx, &*rcvr, PreferMutLvalue);
2924+
check_expr_with_lvalue_pref(fcx, &*rcvr, lvalue_pref);
29272925

29282926
// no need to check for bot/err -- callee does that
29292927
let expr_t = structurally_resolved_type(fcx,
@@ -4141,7 +4139,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
41414139
}
41424140
}
41434141
ast::ExprMethodCall(ident, ref tps, ref args) => {
4144-
check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice());
4142+
check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice(), lvalue_pref);
41454143
let mut arg_tys = args.iter().map(|a| fcx.expr_ty(&**a));
41464144
let (args_bot, args_err) = arg_tys.fold((false, false),
41474145
|(rest_bot, rest_err), a| {

src/test/run-pass/overloaded-deref-count.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,10 @@ pub fn main() {
6868
*n -= 3; // Mutable deref + assignment with binary operation.
6969
assert_eq!(n.counts(), (2, 3));
7070

71-
// Mutable deref used for calling a method taking &self.
72-
// N.B. This is required because method lookup hasn't been performed so
73-
// we don't know whether the called method takes mutable self, before
74-
// the dereference itself is type-checked (a chicken-and-egg problem).
71+
// Immutable deref used for calling a method taking &self. (The
72+
// typechecker is smarter now about doing this.)
7573
(*n).to_string();
76-
assert_eq!(n.counts(), (2, 4));
74+
assert_eq!(n.counts(), (3, 3));
7775

7876
// Mutable deref used for calling a method taking &mut self.
7977
(*v).push(2);

0 commit comments

Comments
 (0)