Skip to content

Commit 7c2526a

Browse files
committed
Be more obvious when suggesting dereference
Include enclosing span when suggesting dereference on a span that is already a reference: ``` error: non-reference pattern used to match a reference (see issue #42640) --> dont-suggest-dereference-on-arg.rs:16:19 | 16 | .filter(|&(ref a, _)| foo(a)) | ^^^^^^^^^^^ help: consider using: `&&(ref k, _)` | = help: add #![feature(match_default_bindings)] to the crate attributes to enable ```
1 parent 71da1c2 commit 7c2526a

File tree

4 files changed

+66
-9
lines changed

4 files changed

+66
-9
lines changed

src/librustc_typeck/check/_match.rs

+26-9
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ use std::collections::hash_map::Entry::{Occupied, Vacant};
2323
use std::cmp;
2424
use syntax::ast;
2525
use syntax::codemap::Spanned;
26+
use syntax::errors::DiagnosticBuilder;
2627
use syntax::feature_gate;
28+
use syntax::parse::ParseSess;
2729
use syntax::ptr::P;
2830
use syntax_pos::Span;
2931

@@ -120,17 +122,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
120122
.pat_adjustments_mut()
121123
.insert(pat.hir_id, pat_adjustments);
122124
} else {
123-
let mut err = feature_gate::feature_err(
124-
&tcx.sess.parse_sess,
125-
"match_default_bindings",
126-
pat.span,
127-
feature_gate::GateIssue::Language,
128-
"non-reference pattern used to match a reference",
129-
);
125+
fn feature_err<'a>(sp: Span, sess: &'a ParseSess) -> DiagnosticBuilder<'a> {
126+
feature_gate::feature_err(
127+
sess,
128+
"match_default_bindings",
129+
sp,
130+
feature_gate::GateIssue::Language,
131+
"non-reference pattern used to match a reference",
132+
)
133+
}
130134
if let Ok(snippet) = tcx.sess.codemap().span_to_snippet(pat.span) {
131-
err.span_suggestion(pat.span, "consider using", format!("&{}", &snippet));
135+
// The following is a bit of a hack. We probably should check the AST for
136+
// this instead, but this should be good enough for the expected cases.
137+
let prev_span = pat.span.prev_point();
138+
let (sp, sugg) = match tcx.sess.codemap().span_to_snippet(prev_span) {
139+
// Make the suggestion more obvious when having `&(_, _)`
140+
Ok(ref prev) if &*prev == "&" => {
141+
(prev_span.to(pat.span), format!("&&{}", &snippet)),
142+
}
143+
_ => (pat.span, format!("&{}", &snippet)),
144+
};
145+
let mut err = feature_err(sp, &tcx.sess.parse_sess);
146+
err.span_suggestion(sp, "consider using a reference", sugg);
147+
err.emit();
148+
} else {
149+
feature_err(pat.span, &tcx.sess.parse_sess).emit();
132150
}
133-
err.emit();
134151
}
135152
}
136153
}

src/libsyntax_pos/lib.rs

+12
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,18 @@ impl Span {
159159
Span::new(BytePos(lo), BytePos(lo), span.ctxt)
160160
}
161161

162+
/// Returns a new span representing the previous character after the start-point of this span
163+
pub fn prev_point(self) -> Span {
164+
let span = self.data();
165+
let span_lo = span.lo.0;
166+
let lo = if span_lo == 0 {
167+
0
168+
} else {
169+
span_lo - 1
170+
};
171+
Span::new(BytePos(lo), BytePos(span_lo), span.ctxt)
172+
}
173+
162174
/// Returns `self` if `self` is not the dummy span, and `other` otherwise.
163175
pub fn substitute_dummy(self, other: Span) -> Span {
164176
if self.source_equal(&DUMMY_SP) { other } else { self }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2017 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+
fn foo(s: &str) -> bool { true }
12+
13+
fn main() {
14+
let x = vec![(String::new(), String::new())];
15+
x.iter()
16+
.filter(|&(ref a, _)| foo(a))
17+
.collect();
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: non-reference pattern used to match a reference (see issue #42640)
2+
--> dont-suggest-dereference-on-arg.rs:16:19
3+
|
4+
16 | .filter(|&(ref a, _)| foo(a))
5+
| ^^^^^^^^^^^ help: consider using: `&&(ref k, _)`
6+
|
7+
= help: add #![feature(match_default_bindings)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+

0 commit comments

Comments
 (0)