Skip to content

Commit 39011f8

Browse files
committed
fix handling of self
1 parent 50728e5 commit 39011f8

File tree

5 files changed

+143
-38
lines changed

5 files changed

+143
-38
lines changed

src/librustc/hir/lowering.rs

+7
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,13 @@ impl<'a> LoweringContext<'a> {
907907
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
908908
},
909909
variadic: decl.variadic,
910+
has_implicit_self: decl.inputs.get(0).map_or(false, |arg| {
911+
match arg.ty.node {
912+
TyKind::ImplicitSelf => true,
913+
TyKind::Rptr(_, ref mt) => mt.ty.node == TyKind::ImplicitSelf,
914+
_ => false
915+
}
916+
})
910917
})
911918
}
912919

src/librustc/hir/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1379,6 +1379,9 @@ pub struct FnDecl {
13791379
pub inputs: HirVec<P<Ty>>,
13801380
pub output: FunctionRetTy,
13811381
pub variadic: bool,
1382+
/// True if this function has an `self`, `&self` or `&mut self` receiver
1383+
/// (but not a `self: Xxx` one).
1384+
pub has_implicit_self: bool,
13821385
}
13831386

13841387
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]

src/librustc_borrowck/borrowck/mod.rs

+31-29
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ use std::fmt;
4242
use std::rc::Rc;
4343
use std::hash::{Hash, Hasher};
4444
use syntax::ast;
45-
use syntax::symbol::keywords;
4645
use syntax_pos::{MultiSpan, Span};
4746
use errors::DiagnosticBuilder;
4847

@@ -809,32 +808,33 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
809808
}
810809

811810
/// Given a type, if it is an immutable reference, return a suggestion to make it mutable
812-
fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option<String> {
811+
fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option<String> {
813812
// Check wether the argument is an immutable reference
813+
debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self);
814814
if let hir::TyRptr(lifetime, hir::MutTy {
815815
mutbl: hir::Mutability::MutImmutable,
816816
ref ty
817817
}) = pty.node {
818818
// Account for existing lifetimes when generating the message
819-
if !lifetime.is_elided() {
820-
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(ty.span) {
821-
if let Ok(lifetime_snippet) = self.tcx.sess.codemap()
822-
.span_to_snippet(lifetime.span) {
823-
return Some(format!("use `&{} mut {}` here to make mutable",
824-
lifetime_snippet,
825-
snippet));
826-
}
827-
}
828-
} else if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(pty.span) {
829-
if snippet.starts_with("&") {
830-
return Some(format!("use `{}` here to make mutable",
831-
snippet.replace("&", "&mut ")));
832-
}
819+
let pointee_snippet = match self.tcx.sess.codemap().span_to_snippet(ty.span) {
820+
Ok(snippet) => snippet,
821+
_ => return None
822+
};
823+
824+
let lifetime_snippet = if !lifetime.is_elided() {
825+
format!("{} ", match self.tcx.sess.codemap().span_to_snippet(lifetime.span) {
826+
Ok(lifetime_snippet) => lifetime_snippet,
827+
_ => return None
828+
})
833829
} else {
834-
bug!("couldn't find a snippet for span: {:?}", pty.span);
835-
}
830+
String::new()
831+
};
832+
Some(format!("use `&{}mut {}` here to make mutable",
833+
lifetime_snippet,
834+
if is_implicit_self { "self" } else { &*pointee_snippet }))
835+
} else {
836+
None
836837
}
837-
None
838838
}
839839

840840
fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode {
@@ -849,24 +849,25 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
849849
}
850850
}
851851

852-
fn local_ty(&self, node_id: ast::NodeId) -> Option<&hir::Ty> {
852+
fn local_ty(&self, node_id: ast::NodeId) -> (Option<&hir::Ty>, bool) {
853853
let parent = self.tcx.hir.get_parent_node(node_id);
854854
let parent_node = self.tcx.hir.get(parent);
855855

856856
// The parent node is like a fn
857857
if let Some(fn_like) = FnLikeNode::from_node(parent_node) {
858858
// `nid`'s parent's `Body`
859859
let fn_body = self.tcx.hir.body(fn_like.body());
860-
// Get the position of `nid` in the arguments list
860+
// Get the position of `node_id` in the arguments list
861861
let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id);
862862
if let Some(i) = arg_pos {
863863
// The argument's `Ty`
864-
Some(&fn_like.decl().inputs[i])
864+
(Some(&fn_like.decl().inputs[i]),
865+
i == 0 && fn_like.decl().has_implicit_self)
865866
} else {
866-
None
867+
(None, false)
867868
}
868869
} else {
869-
None
870+
(None, false)
870871
}
871872
}
872873

@@ -880,8 +881,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
880881
let let_span = self.tcx.hir.span(node_id);
881882
if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) {
882883
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
883-
if self.tcx.hir.name(node_id) == keywords::SelfValue.name() &&
884-
snippet != "self" {
884+
let (_, is_implicit_self) = self.local_ty(node_id);
885+
if is_implicit_self && snippet != "self" {
885886
// avoid suggesting `mut &self`.
886887
return
887888
}
@@ -906,8 +907,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
906907
}
907908
}
908909
hir::BindingMode::BindByValue(..) => {
909-
if let Some(local_ty) = self.local_ty(node_id) {
910-
if let Some(msg) = self.suggest_mut_for_immutable(local_ty) {
910+
if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) {
911+
if let Some(msg) =
912+
self.suggest_mut_for_immutable(local_ty, is_implicit_self) {
911913
db.span_label(local_ty.span, &msg);
912914
}
913915
}
@@ -921,7 +923,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
921923
};
922924

923925
if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) {
924-
if let Some(msg) = self.suggest_mut_for_immutable(&field.ty) {
926+
if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) {
925927
db.span_label(field.ty.span, &msg);
926928
}
927929
}

src/test/ui/did_you_mean/issue-39544.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,37 @@ pub struct Z {
1616
x: X
1717
}
1818

19-
pub fn main() {
19+
fn main() {
2020
let z = Z { x: X::Y };
2121
let _ = &mut z.x;
2222
}
2323

24+
impl Z {
25+
fn foo<'z>(&'z self) {
26+
let _ = &mut self.x;
27+
}
28+
29+
fn foo1(&self, other: &Z) {
30+
let _ = &mut self.x;
31+
let _ = &mut other.x;
32+
}
33+
34+
fn foo2<'a>(&'a self, other: &Z) {
35+
let _ = &mut self.x;
36+
let _ = &mut other.x;
37+
}
38+
39+
fn foo3<'a>(self: &'a Self, other: &Z) {
40+
let _ = &mut self.x;
41+
let _ = &mut other.x;
42+
}
43+
44+
fn foo4(other: &Z) {
45+
let _ = &mut other.x;
46+
}
47+
48+
}
49+
2450
pub fn with_arg(z: Z, w: &Z) {
2551
let _ = &mut z.x;
2652
let _ = &mut w.x;

src/test/ui/did_you_mean/issue-39544.stderr

+75-8
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,89 @@ error: cannot borrow immutable field `z.x` as mutable
66
21 | let _ = &mut z.x;
77
| ^^^ cannot mutably borrow immutable field
88

9+
error: cannot borrow immutable field `self.x` as mutable
10+
--> $DIR/issue-39544.rs:26:22
11+
|
12+
25 | fn foo<'z>(&'z self) {
13+
| -------- use `&'z mut self` here to make mutable
14+
26 | let _ = &mut self.x;
15+
| ^^^^^^ cannot mutably borrow immutable field
16+
17+
error: cannot borrow immutable field `self.x` as mutable
18+
--> $DIR/issue-39544.rs:30:22
19+
|
20+
29 | fn foo1(&self, other: &Z) {
21+
| ----- use `&mut self` here to make mutable
22+
30 | let _ = &mut self.x;
23+
| ^^^^^^ cannot mutably borrow immutable field
24+
25+
error: cannot borrow immutable field `other.x` as mutable
26+
--> $DIR/issue-39544.rs:31:22
27+
|
28+
29 | fn foo1(&self, other: &Z) {
29+
| -- use `&mut Z` here to make mutable
30+
30 | let _ = &mut self.x;
31+
31 | let _ = &mut other.x;
32+
| ^^^^^^^ cannot mutably borrow immutable field
33+
34+
error: cannot borrow immutable field `self.x` as mutable
35+
--> $DIR/issue-39544.rs:35:22
36+
|
37+
34 | fn foo2<'a>(&'a self, other: &Z) {
38+
| -------- use `&'a mut self` here to make mutable
39+
35 | let _ = &mut self.x;
40+
| ^^^^^^ cannot mutably borrow immutable field
41+
42+
error: cannot borrow immutable field `other.x` as mutable
43+
--> $DIR/issue-39544.rs:36:22
44+
|
45+
34 | fn foo2<'a>(&'a self, other: &Z) {
46+
| -- use `&mut Z` here to make mutable
47+
35 | let _ = &mut self.x;
48+
36 | let _ = &mut other.x;
49+
| ^^^^^^^ cannot mutably borrow immutable field
50+
51+
error: cannot borrow immutable field `self.x` as mutable
52+
--> $DIR/issue-39544.rs:40:22
53+
|
54+
39 | fn foo3<'a>(self: &'a Self, other: &Z) {
55+
| -------- use `&'a mut Self` here to make mutable
56+
40 | let _ = &mut self.x;
57+
| ^^^^^^ cannot mutably borrow immutable field
58+
59+
error: cannot borrow immutable field `other.x` as mutable
60+
--> $DIR/issue-39544.rs:41:22
61+
|
62+
39 | fn foo3<'a>(self: &'a Self, other: &Z) {
63+
| -- use `&mut Z` here to make mutable
64+
40 | let _ = &mut self.x;
65+
41 | let _ = &mut other.x;
66+
| ^^^^^^^ cannot mutably borrow immutable field
67+
68+
error: cannot borrow immutable field `other.x` as mutable
69+
--> $DIR/issue-39544.rs:45:22
70+
|
71+
44 | fn foo4(other: &Z) {
72+
| -- use `&mut Z` here to make mutable
73+
45 | let _ = &mut other.x;
74+
| ^^^^^^^ cannot mutably borrow immutable field
75+
976
error: cannot borrow immutable field `z.x` as mutable
10-
--> $DIR/issue-39544.rs:25:18
77+
--> $DIR/issue-39544.rs:51:18
1178
|
12-
24 | pub fn with_arg(z: Z, w: &Z) {
79+
50 | pub fn with_arg(z: Z, w: &Z) {
1380
| - consider changing this to `mut z`
14-
25 | let _ = &mut z.x;
81+
51 | let _ = &mut z.x;
1582
| ^^^ cannot mutably borrow immutable field
1683

1784
error: cannot borrow immutable field `w.x` as mutable
18-
--> $DIR/issue-39544.rs:26:18
85+
--> $DIR/issue-39544.rs:52:18
1986
|
20-
24 | pub fn with_arg(z: Z, w: &Z) {
87+
50 | pub fn with_arg(z: Z, w: &Z) {
2188
| -- use `&mut Z` here to make mutable
22-
25 | let _ = &mut z.x;
23-
26 | let _ = &mut w.x;
89+
51 | let _ = &mut z.x;
90+
52 | let _ = &mut w.x;
2491
| ^^^ cannot mutably borrow immutable field
2592

26-
error: aborting due to 3 previous errors
93+
error: aborting due to 11 previous errors
2794

0 commit comments

Comments
 (0)