Skip to content

Commit 60e7317

Browse files
committed
auto merge of #17501 : pcwalton/rust/improve-method-lookup-autoderef, r=nikomatsakis
prefer `Deref` over `DerefMut` in all other circumstances. Because the compiler now prefers `Deref`, this can break code that looked like: let mut foo = bar.borrow_mut(); (*foo).call_something_that_requires_mutable_self(); Replace this code with: let mut foo = bar.baz(); (&mut *foo).call_something_that_requires_mutable_self(); Closes #12825. [breaking-change] r? @nikomatsakis
2 parents fe93a54 + 496cc4c commit 60e7317

File tree

8 files changed

+154
-10
lines changed

8 files changed

+154
-10
lines changed

src/libgreen/basic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl EventLoop for BasicLoop {
116116
}
117117

118118
unsafe {
119-
let mut messages = self.messages.lock();
119+
let messages = self.messages.lock();
120120
// We block here if we have no messages to process and we may
121121
// receive a message at a later date
122122
if self.remotes.len() > 0 && messages.len() == 0 &&

src/librustc/middle/mem_categorization.rs

+11
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
405405
Some(adjustment) => {
406406
match *adjustment {
407407
ty::AdjustAddEnv(..) => {
408+
debug!("cat_expr(AdjustAddEnv): {}",
409+
expr.repr(self.tcx()));
408410
// Convert a bare fn to a closure by adding NULL env.
409411
// Result is an rvalue.
410412
let expr_ty = if_ok!(self.expr_ty_adjusted(expr));
@@ -414,6 +416,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
414416
ty::AdjustDerefRef(
415417
ty::AutoDerefRef {
416418
autoref: Some(_), ..}) => {
419+
debug!("cat_expr(AdjustDerefRef): {}",
420+
expr.repr(self.tcx()));
417421
// Equivalent to &*expr or something similar.
418422
// Result is an rvalue.
419423
let expr_ty = if_ok!(self.expr_ty_adjusted(expr));
@@ -436,6 +440,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
436440
autoderefs: uint)
437441
-> McResult<cmt> {
438442
let mut cmt = if_ok!(self.cat_expr_unadjusted(expr));
443+
debug!("cat_expr_autoderefd: autoderefs={}, cmt={}",
444+
autoderefs,
445+
cmt.repr(self.tcx()));
439446
for deref in range(1u, autoderefs + 1) {
440447
cmt = self.cat_deref(expr, cmt, deref, false);
441448
}
@@ -454,6 +461,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
454461

455462
ast::ExprField(ref base, f_name, _) => {
456463
let base_cmt = if_ok!(self.cat_expr(&**base));
464+
debug!("cat_expr(cat_field): id={} expr={} base={}",
465+
expr.id,
466+
expr.repr(self.tcx()),
467+
base_cmt.repr(self.tcx()));
457468
Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty))
458469
}
459470

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

+83-7
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,11 @@ use middle::traits;
8686
use middle::ty::*;
8787
use middle::ty;
8888
use middle::typeck::astconv::AstConv;
89-
use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
89+
use middle::typeck::check::{FnCtxt, NoPreference, PreferMutLvalue};
90+
use middle::typeck::check::{impl_self_ty};
9091
use middle::typeck::check;
9192
use middle::typeck::infer;
92-
use middle::typeck::MethodCallee;
93+
use middle::typeck::{MethodCall, MethodCallee};
9394
use middle::typeck::{MethodOrigin, MethodParam, MethodTypeParam};
9495
use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject, MethodTraitObject};
9596
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
@@ -353,11 +354,15 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
353354

354355
let (_, _, result) =
355356
check::autoderef(
356-
self.fcx, span, self_ty, self_expr_id, PreferMutLvalue,
357+
self.fcx, span, self_ty, self_expr_id, NoPreference,
357358
|self_ty, autoderefs| self.search_step(self_ty, autoderefs));
358359

359360
match result {
360-
Some(Some(result)) => Some(result),
361+
Some(Some(result)) => {
362+
self.fixup_derefs_on_method_receiver_if_necessary(&result,
363+
self_ty);
364+
Some(result)
365+
}
361366
_ => None
362367
}
363368
}
@@ -430,7 +435,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
430435
*/
431436

432437
let span = self.self_expr.map_or(self.span, |e| e.span);
433-
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
438+
check::autoderef(self.fcx, span, self_ty, None, NoPreference, |self_ty, _| {
434439
match get(self_ty).sty {
435440
ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => {
436441
self.push_inherent_candidates_from_object(
@@ -458,7 +463,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
458463

459464
fn push_bound_candidates(&mut self, self_ty: ty::t, restrict_to: Option<DefId>) {
460465
let span = self.self_expr.map_or(self.span, |e| e.span);
461-
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
466+
check::autoderef(self.fcx, span, self_ty, None, NoPreference, |self_ty, _| {
462467
match get(self_ty).sty {
463468
ty_param(p) => {
464469
self.push_inherent_candidates_from_param(self_ty, restrict_to, p);
@@ -1135,7 +1140,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
11351140
};
11361141

11371142
// This is hokey. We should have mutability inference as a
1138-
// variable. But for now, try &const, then &, then &mut:
1143+
// variable. But for now, try &, then &mut:
11391144
let region =
11401145
self.infcx().next_region_var(infer::Autoref(self.span));
11411146
for mutbl in mutbls.iter() {
@@ -1381,6 +1386,77 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
13811386
}
13821387
}
13831388

1389+
fn fixup_derefs_on_method_receiver_if_necessary(
1390+
&self,
1391+
method_callee: &MethodCallee,
1392+
self_ty: ty::t) {
1393+
let sig = match ty::get(method_callee.ty).sty {
1394+
ty::ty_bare_fn(ref f) => f.sig.clone(),
1395+
ty::ty_closure(ref f) => f.sig.clone(),
1396+
_ => return,
1397+
};
1398+
1399+
match ty::get(*sig.inputs.get(0)).sty {
1400+
ty::ty_rptr(_, ty::mt {
1401+
ty: _,
1402+
mutbl: ast::MutMutable,
1403+
}) => {}
1404+
_ => return,
1405+
}
1406+
1407+
// Fix up autoderefs and derefs.
1408+
let mut self_expr = match self.self_expr {
1409+
Some(expr) => expr,
1410+
None => return,
1411+
};
1412+
loop {
1413+
// Count autoderefs.
1414+
let autoderef_count = match self.fcx
1415+
.inh
1416+
.adjustments
1417+
.borrow()
1418+
.find(&self_expr.id) {
1419+
Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
1420+
autoderefs: autoderef_count,
1421+
autoref: _
1422+
})) if autoderef_count > 0 => autoderef_count,
1423+
Some(_) | None => return,
1424+
};
1425+
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
1454+
}
1455+
_ => break,
1456+
}
1457+
}
1458+
}
1459+
13841460
fn enforce_object_limitations(&self, candidate: &Candidate) {
13851461
/*!
13861462
* There are some limitations to calling functions through an

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

+1
Original file line numberDiff line numberDiff line change
@@ -2078,6 +2078,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20782078
}
20792079
}
20802080

2081+
#[deriving(Show)]
20812082
pub enum LvaluePreference {
20822083
PreferMutLvalue,
20832084
NoPreference

src/libsyntax/codemap.rs

+5
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@ impl FileMap {
290290
}
291291

292292
/// get a line from the list of pre-computed line-beginnings
293+
///
294+
/// NOTE(stage0, pcwalton): Remove `#[allow(unused_mut)]` after snapshot.
295+
#[allow(unused_mut)]
293296
pub fn get_line(&self, line: int) -> String {
294297
let mut lines = self.lines.borrow_mut();
295298
let begin: BytePos = *lines.get(line as uint) - self.start_pos;
@@ -512,6 +515,8 @@ impl CodeMap {
512515
return a;
513516
}
514517

518+
// NOTE(stage0, pcwalton): Remove `#[allow(unused_mut)]` after snapshot.
519+
#[allow(unused_mut)]
515520
fn lookup_line(&self, pos: BytePos) -> FileMapAndLine {
516521
let idx = self.lookup_filemap_idx(pos);
517522

src/test/run-pass/dst-deref-mut.rs

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ impl DerefMut<[uint]> for Arr {
2727
}
2828

2929
pub fn foo(arr: &mut Arr) {
30-
assert!(arr.len() == 3);
3130
let x: &mut [uint] = &mut **arr;
3231
assert!(x[0] == 1);
3332
assert!(x[1] == 2);

src/test/run-pass/fixup-deref-mut.rs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Generic unique/owned smaht pointer.
12+
struct Own<T> {
13+
value: *mut T
14+
}
15+
16+
impl<T> Deref<T> for Own<T> {
17+
fn deref<'a>(&'a self) -> &'a T {
18+
unsafe { &*self.value }
19+
}
20+
}
21+
22+
impl<T> DerefMut<T> for Own<T> {
23+
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
24+
unsafe { &mut *self.value }
25+
}
26+
}
27+
28+
struct Point {
29+
x: int,
30+
y: int
31+
}
32+
33+
impl Point {
34+
fn get(&mut self) -> (int, int) {
35+
(self.x, self.y)
36+
}
37+
}
38+
39+
fn test0(mut x: Own<Point>) {
40+
let _ = x.get();
41+
}
42+
43+
fn test1(mut x: Own<Own<Own<Point>>>) {
44+
let _ = x.get();
45+
}
46+
47+
fn test2(mut x: Own<Own<Own<Point>>>) {
48+
let _ = (**x).get();
49+
}
50+
51+
fn main() {}
52+

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub fn main() {
7474
assert_eq!(p.counts(), (2, 2));
7575

7676
p.get();
77-
assert_eq!(p.counts(), (2, 3));
77+
assert_eq!(p.counts(), (3, 2));
7878

7979
// Check the final state.
8080
assert_eq!(*p, Point {x: 3, y: 0});

0 commit comments

Comments
 (0)