diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-08-27 23:44:44 +0200 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-08-27 23:44:44 +0200 |
| commit | 42e895d4d99ec7724f3efd632f52170f3f99a5aa (patch) | |
| tree | ee1a9de1892767097e8a7ce767191648c78ef3a5 /src/libsyntax/parse | |
| parent | dbbe3363c94b120d1eba9cba01dadddd862716b8 (diff) | |
| download | rust-42e895d4d99ec7724f3efd632f52170f3f99a5aa.tar.gz rust-42e895d4d99ec7724f3efd632f52170f3f99a5aa.zip | |
Improve 'mut ' diagnostic.
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/parser/pat.rs | 54 |
1 files changed, 34 insertions, 20 deletions
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 08934e85330..1ffb112a5e8 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -405,22 +405,13 @@ impl<'a> Parser<'a> { let mut pat = self.parse_pat(Some("identifier"))?; // Add `mut` to any binding in the parsed pattern. - struct AddMut; - impl MutVisitor for AddMut { - fn visit_pat(&mut self, pat: &mut P<Pat>) { - if let PatKind::Ident(BindingMode::ByValue(ref mut m), ..) = pat.node { - *m = Mutability::Mutable; - } - noop_visit_pat(pat, self); - } - } - AddMut.visit_pat(&mut pat); + let changed_any_binding = Self::make_all_value_bindings_mutable(&mut pat); // Unwrap; If we don't have `mut $ident`, error. let pat = pat.into_inner(); match &pat.node { PatKind::Ident(..) => {} - _ => self.ban_mut_general_pat(mut_span, &pat), + _ => self.ban_mut_general_pat(mut_span, &pat, changed_any_binding), } Ok(pat.node) @@ -442,17 +433,40 @@ impl<'a> Parser<'a> { self.parse_pat_ident(BindingMode::ByRef(Mutability::Mutable)) } + /// Turn all by-value immutable bindings in a pattern into mutable bindings. + /// Returns `true` if any change was made. + fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool { + struct AddMut(bool); + impl MutVisitor for AddMut { + fn visit_pat(&mut self, pat: &mut P<Pat>) { + if let PatKind::Ident(BindingMode::ByValue(ref mut m @ Mutability::Immutable), ..) + = pat.node + { + *m = Mutability::Mutable; + self.0 = true; + } + noop_visit_pat(pat, self); + } + } + + let mut add_mut = AddMut(false); + add_mut.visit_pat(pat); + add_mut.0 + } + /// Error on `mut $pat` where `$pat` is not an ident. - fn ban_mut_general_pat(&self, lo: Span, pat: &Pat) { + fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) { let span = lo.to(pat.span); - self.struct_span_err(span, "`mut` must be attached to each individual binding") - .span_suggestion( - span, - "add `mut` to each binding", - pprust::pat_to_string(&pat), - Applicability::MachineApplicable, - ) - .emit(); + let fix = pprust::pat_to_string(&pat); + let (problem, suggestion) = if changed_any_binding { + ("`mut` must be attached to each individual binding", "add `mut` to each binding") + } else { + ("`mut` must be followed by a named binding", "remove the `mut` prefix") + }; + self.struct_span_err(span, problem) + .span_suggestion(span, suggestion, fix, Applicability::MachineApplicable) + .note("`mut` may be followed by `variable` and `variable @ pattern`") + .emit() } /// Eat any extraneous `mut`s and error + recover if we ate any. |
