Skip to content

Commit 43b5d72

Browse files
committed
Improve implicit self mutability suggestions.
This commit adds an `ImplicitSelfKind` to the HIR and the MIR that keeps track of whether a implicit self argument is immutable by-value, mutable by-value, immutable reference or mutable reference so that the addition of the `mut` keyword can be suggested for the immutable by-value case.
1 parent f55129d commit 43b5d72

File tree

10 files changed

+180
-26
lines changed

10 files changed

+180
-26
lines changed

src/librustc/hir/lowering.rs

+25-5
Original file line numberDiff line numberDiff line change
@@ -2011,11 +2011,31 @@ impl<'a> LoweringContext<'a> {
20112011
inputs,
20122012
output,
20132013
variadic: decl.variadic,
2014-
has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node {
2015-
TyKind::ImplicitSelf => true,
2016-
TyKind::Rptr(_, ref mt) => mt.ty.node.is_implicit_self(),
2017-
_ => false,
2018-
}),
2014+
implicit_self: decl.inputs.get(0).map_or(
2015+
hir::ImplicitSelfKind::None,
2016+
|arg| {
2017+
let is_mutable_pat = match arg.pat.node {
2018+
PatKind::Ident(BindingMode::ByValue(mt), _, _) |
2019+
PatKind::Ident(BindingMode::ByRef(mt), _, _) =>
2020+
mt == Mutability::Mutable,
2021+
_ => false,
2022+
};
2023+
2024+
match arg.ty.node {
2025+
TyKind::ImplicitSelf if is_mutable_pat => hir::ImplicitSelfKind::Mut,
2026+
TyKind::ImplicitSelf => hir::ImplicitSelfKind::Imm,
2027+
// Given we are only considering `ImplicitSelf` types, we needn't consider
2028+
// the case where we have a mutable pattern to a reference as that would
2029+
// no longer be an `ImplicitSelf`.
2030+
TyKind::Rptr(_, ref mt) if mt.ty.node.is_implicit_self() &&
2031+
mt.mutbl == ast::Mutability::Mutable =>
2032+
hir::ImplicitSelfKind::MutRef,
2033+
TyKind::Rptr(_, ref mt) if mt.ty.node.is_implicit_self() =>
2034+
hir::ImplicitSelfKind::ImmRef,
2035+
_ => hir::ImplicitSelfKind::None,
2036+
}
2037+
},
2038+
),
20192039
})
20202040
}
20212041

src/librustc/hir/mod.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -1769,9 +1769,34 @@ pub struct FnDecl {
17691769
pub inputs: HirVec<Ty>,
17701770
pub output: FunctionRetTy,
17711771
pub variadic: bool,
1772-
/// True if this function has an `self`, `&self` or `&mut self` receiver
1773-
/// (but not a `self: Xxx` one).
1774-
pub has_implicit_self: bool,
1772+
/// Does the function have an implicit self?
1773+
pub implicit_self: ImplicitSelfKind,
1774+
}
1775+
1776+
/// Represents what type of implicit self a function has, if any.
1777+
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
1778+
pub enum ImplicitSelfKind {
1779+
/// Represents a `fn x(self);`.
1780+
Imm,
1781+
/// Represents a `fn x(mut self);`.
1782+
Mut,
1783+
/// Represents a `fn x(&self);`.
1784+
ImmRef,
1785+
/// Represents a `fn x(&mut self);`.
1786+
MutRef,
1787+
/// Represents when a function does not have a self argument or
1788+
/// when a function has a `self: X` argument.
1789+
None
1790+
}
1791+
1792+
impl ImplicitSelfKind {
1793+
/// Does this represent an implicit self?
1794+
pub fn has_implicit_self(&self) -> bool {
1795+
match *self {
1796+
ImplicitSelfKind::None => false,
1797+
_ => true,
1798+
}
1799+
}
17751800
}
17761801

17771802
/// Is the trait definition an auto trait?

src/librustc/ich/impls_hir.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -349,14 +349,22 @@ impl_stable_hash_for!(struct hir::FnDecl {
349349
inputs,
350350
output,
351351
variadic,
352-
has_implicit_self
352+
implicit_self
353353
});
354354

355355
impl_stable_hash_for!(enum hir::FunctionRetTy {
356356
DefaultReturn(span),
357357
Return(t)
358358
});
359359

360+
impl_stable_hash_for!(enum hir::ImplicitSelfKind {
361+
Imm,
362+
Mut,
363+
ImmRef,
364+
MutRef,
365+
None
366+
});
367+
360368
impl_stable_hash_for!(struct hir::TraitRef {
361369
// Don't hash the ref_id. It is tracked via the thing it is used to access
362370
ref_id -> _,

src/librustc/mir/mod.rs

+30-7
Original file line numberDiff line numberDiff line change
@@ -583,11 +583,27 @@ pub enum BindingForm<'tcx> {
583583
/// This is a binding for a non-`self` binding, or a `self` that has an explicit type.
584584
Var(VarBindingForm<'tcx>),
585585
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
586-
ImplicitSelf,
586+
ImplicitSelf(ImplicitSelfKind),
587587
/// Reference used in a guard expression to ensure immutability.
588588
RefForGuard,
589589
}
590590

591+
/// Represents what type of implicit self a function has, if any.
592+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
593+
pub enum ImplicitSelfKind {
594+
/// Represents a `fn x(self);`.
595+
Imm,
596+
/// Represents a `fn x(mut self);`.
597+
Mut,
598+
/// Represents a `fn x(&self);`.
599+
ImmRef,
600+
/// Represents a `fn x(&mut self);`.
601+
MutRef,
602+
/// Represents when a function does not have a self argument or
603+
/// when a function has a `self: X` argument.
604+
None
605+
}
606+
591607
CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, }
592608

593609
impl_stable_hash_for!(struct self::VarBindingForm<'tcx> {
@@ -597,6 +613,14 @@ impl_stable_hash_for!(struct self::VarBindingForm<'tcx> {
597613
pat_span
598614
});
599615

616+
impl_stable_hash_for!(enum self::ImplicitSelfKind {
617+
Imm,
618+
Mut,
619+
ImmRef,
620+
MutRef,
621+
None
622+
});
623+
600624
mod binding_form_impl {
601625
use ich::StableHashingContext;
602626
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
@@ -612,7 +636,7 @@ mod binding_form_impl {
612636

613637
match self {
614638
Var(binding) => binding.hash_stable(hcx, hasher),
615-
ImplicitSelf => (),
639+
ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
616640
RefForGuard => (),
617641
}
618642
}
@@ -775,10 +799,9 @@ impl<'tcx> LocalDecl<'tcx> {
775799
pat_span: _,
776800
}))) => true,
777801

778-
// FIXME: might be able to thread the distinction between
779-
// `self`/`mut self`/`&self`/`&mut self` into the
780-
// `BindingForm::ImplicitSelf` variant, (and then return
781-
// true here for solely the first case).
802+
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm)))
803+
=> true,
804+
782805
_ => false,
783806
}
784807
}
@@ -795,7 +818,7 @@ impl<'tcx> LocalDecl<'tcx> {
795818
pat_span: _,
796819
}))) => true,
797820

798-
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true,
821+
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true,
799822

800823
_ => false,
801824
}

src/librustc_borrowck/borrowck/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1221,7 +1221,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
12211221
if let Some(i) = arg_pos {
12221222
// The argument's `Ty`
12231223
(Some(&fn_like.decl().inputs[i]),
1224-
i == 0 && fn_like.decl().has_implicit_self)
1224+
i == 0 && fn_like.decl().implicit_self.has_implicit_self())
12251225
} else {
12261226
(None, false)
12271227
}

src/librustc_mir/borrow_check/mutability_errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
316316
{
317317
let local_decl = &self.mir.local_decls[*local];
318318
let suggestion = match local_decl.is_user_variable.as_ref().unwrap() {
319-
ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf) => {
319+
ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_)) => {
320320
Some(suggest_ampmut_self(self.infcx.tcx, local_decl))
321321
}
322322

src/librustc_mir/build/mod.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,14 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
125125
let ty_hir_id = fn_decl.inputs[index].hir_id;
126126
let ty_span = tcx.hir.span(tcx.hir.hir_to_node_id(ty_hir_id));
127127
opt_ty_info = Some(ty_span);
128-
self_arg = if index == 0 && fn_decl.has_implicit_self {
129-
Some(ImplicitSelfBinding)
128+
self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() {
129+
match fn_decl.implicit_self {
130+
hir::ImplicitSelfKind::Imm => Some(ImplicitSelfKind::Imm),
131+
hir::ImplicitSelfKind::Mut => Some(ImplicitSelfKind::Mut),
132+
hir::ImplicitSelfKind::ImmRef => Some(ImplicitSelfKind::ImmRef),
133+
hir::ImplicitSelfKind::MutRef => Some(ImplicitSelfKind::MutRef),
134+
_ => None,
135+
}
130136
} else {
131137
None
132138
};
@@ -508,12 +514,10 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
508514
///////////////////////////////////////////////////////////////////////////
509515
/// the main entry point for building MIR for a function
510516
511-
struct ImplicitSelfBinding;
512-
513517
struct ArgInfo<'gcx>(Ty<'gcx>,
514518
Option<Span>,
515519
Option<&'gcx hir::Pat>,
516-
Option<ImplicitSelfBinding>);
520+
Option<ImplicitSelfKind>);
517521

518522
fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
519523
fn_id: ast::NodeId,
@@ -797,8 +801,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
797801
PatternKind::Binding { mutability, var, mode: BindingMode::ByValue, .. } => {
798802
self.local_decls[local].mutability = mutability;
799803
self.local_decls[local].is_user_variable =
800-
if let Some(ImplicitSelfBinding) = self_binding {
801-
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf))
804+
if let Some(kind) = self_binding {
805+
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind)))
802806
} else {
803807
let binding_mode = ty::BindingMode::BindByValue(mutability.into());
804808
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {

src/test/incremental/hashes/trait_defs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ trait TraitChangeModeSelfOwnToMut: Sized {
270270
#[rustc_clean(label="Hir", cfg="cfail2")]
271271
#[rustc_clean(label="Hir", cfg="cfail3")]
272272
trait TraitChangeModeSelfOwnToMut: Sized {
273-
#[rustc_clean(label="Hir", cfg="cfail2")]
273+
#[rustc_dirty(label="Hir", cfg="cfail2")]
274274
#[rustc_clean(label="Hir", cfg="cfail3")]
275275
#[rustc_dirty(label="HirBody", cfg="cfail2")]
276276
#[rustc_clean(label="HirBody", cfg="cfail3")]

src/test/ui/nll/issue-51191.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2016 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+
#![feature(nll)]
12+
13+
struct Struct;
14+
15+
impl Struct {
16+
fn bar(self: &mut Self) {
17+
(&mut self).bar(); //~ ERROR cannot borrow
18+
}
19+
20+
fn imm(self) {
21+
(&mut self).bar(); //~ ERROR cannot borrow
22+
}
23+
24+
fn mtbl(mut self) {
25+
(&mut self).bar();
26+
}
27+
28+
fn immref(&self) {
29+
(&mut self).bar(); //~ ERROR cannot borrow
30+
}
31+
32+
fn mtblref(&mut self) {
33+
(&mut self).bar();
34+
}
35+
}
36+
37+
fn main () {}

src/test/ui/nll/issue-51191.stderr

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
2+
--> $DIR/issue-51191.rs:17:9
3+
|
4+
LL | fn bar(self: &mut Self) {
5+
| ---- help: consider changing this to be mutable: `mut self`
6+
LL | (&mut self).bar(); //~ ERROR cannot borrow
7+
| ^^^^^^^^^^^ cannot borrow as mutable
8+
9+
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
10+
--> $DIR/issue-51191.rs:21:9
11+
|
12+
LL | fn imm(self) {
13+
| ---- help: consider changing this to be mutable: `mut self`
14+
LL | (&mut self).bar(); //~ ERROR cannot borrow
15+
| ^^^^^^^^^^^ cannot borrow as mutable
16+
17+
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
18+
--> $DIR/issue-51191.rs:29:9
19+
|
20+
LL | (&mut self).bar(); //~ ERROR cannot borrow
21+
| ^^^^^^^^^^^ cannot borrow as mutable
22+
23+
error[E0596]: cannot borrow data in a `&` reference as mutable
24+
--> $DIR/issue-51191.rs:29:9
25+
|
26+
LL | (&mut self).bar(); //~ ERROR cannot borrow
27+
| ^^^^^^^^^^^ cannot borrow as mutable
28+
29+
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
30+
--> $DIR/issue-51191.rs:33:9
31+
|
32+
LL | (&mut self).bar();
33+
| ^^^^^^^^^^^ cannot borrow as mutable
34+
35+
error: aborting due to 5 previous errors
36+
37+
For more information about this error, try `rustc --explain E0596`.

0 commit comments

Comments
 (0)