Skip to content

Commit 52fbd3e

Browse files
committed
Increase verbosity when suggesting subtle code changes
1 parent 5ae85f4 commit 52fbd3e

32 files changed

+360
-239
lines changed

src/librustc_infer/infer/error_reporting/need_type_info.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::infer::InferCtxt;
33
use rustc::hir::map::Map;
44
use rustc::ty::print::Print;
55
use rustc::ty::{self, DefIdTree, Infer, Ty, TyVar};
6-
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
6+
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
77
use rustc_hir as hir;
88
use rustc_hir::def::{DefKind, Namespace};
99
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
@@ -462,24 +462,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
462462
e: &Expr<'_>,
463463
err: &mut DiagnosticBuilder<'_>,
464464
) {
465-
if let (Ok(snippet), Some(tables), None) = (
466-
self.tcx.sess.source_map().span_to_snippet(segment.ident.span),
467-
self.in_progress_tables,
468-
&segment.args,
469-
) {
465+
if let (Some(tables), None) = (self.in_progress_tables, &segment.args) {
470466
let borrow = tables.borrow();
471467
if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
472468
let generics = self.tcx.generics_of(did);
473469
if !generics.params.is_empty() {
474-
err.span_suggestion(
475-
segment.ident.span,
470+
err.span_suggestion_verbose(
471+
segment.ident.span.shrink_to_hi(),
476472
&format!(
477473
"consider specifying the type argument{} in the method call",
478-
if generics.params.len() > 1 { "s" } else { "" },
474+
pluralize!(generics.params.len()),
479475
),
480476
format!(
481-
"{}::<{}>",
482-
snippet,
477+
"::<{}>",
483478
generics
484479
.params
485480
.iter()

src/librustc_trait_selection/traits/error_reporting/mod.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -815,11 +815,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
815815
// For example, if `expected_args_length` is 2, suggest `|_, _|`.
816816
if found_args.is_empty() && is_closure {
817817
let underscores = vec!["_"; expected_args.len()].join(", ");
818-
err.span_suggestion(
818+
err.span_suggestion_verbose(
819819
pipe_span,
820820
&format!(
821821
"consider changing the closure to take and ignore the expected argument{}",
822-
if expected_args.len() < 2 { "" } else { "s" }
822+
pluralize!(expected_args.len())
823823
),
824824
format!("|{}|", underscores),
825825
Applicability::MachineApplicable,
@@ -833,7 +833,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
833833
.map(|(name, _)| name.to_owned())
834834
.collect::<Vec<String>>()
835835
.join(", ");
836-
err.span_suggestion(
836+
err.span_suggestion_verbose(
837837
found_span,
838838
"change the closure to take multiple arguments instead of a single tuple",
839839
format!("|{}|", sugg),
@@ -870,7 +870,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
870870
String::new()
871871
},
872872
);
873-
err.span_suggestion(
873+
err.span_suggestion_verbose(
874874
found_span,
875875
"change the closure to accept a tuple instead of individual arguments",
876876
sugg,
@@ -1420,15 +1420,14 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
14201420
// |
14211421
// = note: cannot resolve `_: Tt`
14221422

1423-
err.span_suggestion(
1424-
span,
1423+
err.span_suggestion_verbose(
1424+
span.shrink_to_hi(),
14251425
&format!(
14261426
"consider specifying the type argument{} in the function call",
1427-
if generics.params.len() > 1 { "s" } else { "" },
1427+
pluralize!(generics.params.len()),
14281428
),
14291429
format!(
1430-
"{}::<{}>",
1431-
snippet,
1430+
"::<{}>",
14321431
generics
14331432
.params
14341433
.iter()
@@ -1590,7 +1589,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
15901589
[] => (span.shrink_to_hi(), ":"),
15911590
[.., bound] => (bound.span().shrink_to_hi(), " + "),
15921591
};
1593-
err.span_suggestion(
1592+
err.span_suggestion_verbose(
15941593
span,
15951594
"consider relaxing the implicit `Sized` restriction",
15961595
format!("{} ?Sized", separator),

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
390390
}
391391
let hir = self.tcx.hir();
392392
// Get the name of the callable and the arguments to be used in the suggestion.
393-
let snippet = match hir.get_if_local(def_id) {
393+
let (snippet, sugg) = match hir.get_if_local(def_id) {
394394
Some(hir::Node::Expr(hir::Expr {
395395
kind: hir::ExprKind::Closure(_, decl, _, span, ..),
396396
..
@@ -401,7 +401,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
401401
None => return,
402402
};
403403
let args = decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
404-
format!("{}({})", name, args)
404+
let sugg = format!("({})", args);
405+
(format!("{}{}", name, sugg), sugg)
405406
}
406407
Some(hir::Node::Item(hir::Item {
407408
ident,
@@ -422,7 +423,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
422423
})
423424
.collect::<Vec<_>>()
424425
.join(", ");
425-
format!("{}({})", ident, args)
426+
let sugg = format!("({})", args);
427+
(format!("{}{}", ident, sugg), sugg)
426428
}
427429
_ => return,
428430
};
@@ -431,10 +433,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
431433
// an argument, the `obligation.cause.span` points at the expression
432434
// of the argument, so we can provide a suggestion. This is signaled
433435
// by `points_at_arg`. Otherwise, we give a more general note.
434-
err.span_suggestion(
435-
obligation.cause.span,
436+
err.span_suggestion_verbose(
437+
obligation.cause.span.shrink_to_hi(),
436438
&msg,
437-
snippet,
439+
sugg,
438440
Applicability::HasPlaceholders,
439441
);
440442
} else {
@@ -619,7 +621,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
619621
.source_map()
620622
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
621623
if points_at_arg && mutability == hir::Mutability::Not && refs_number > 0 {
622-
err.span_suggestion(
624+
err.span_suggestion_verbose(
623625
sp,
624626
"consider changing this borrow's mutability",
625627
"&mut ".to_string(),

src/librustc_typeck/check/method/mod.rs

+11-17
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137137
self_ty: Ty<'tcx>,
138138
call_expr: &hir::Expr<'_>,
139139
) {
140-
let has_params = self
140+
let params = self
141141
.probe_for_name(
142142
method_name.span,
143143
probe::Mode::MethodCall,
@@ -147,26 +147,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
147147
call_expr.hir_id,
148148
ProbeScope::TraitsInScope,
149149
)
150-
.and_then(|pick| {
150+
.map(|pick| {
151151
let sig = self.tcx.fn_sig(pick.item.def_id);
152-
Ok(sig.inputs().skip_binder().len() > 1)
153-
});
152+
sig.inputs().skip_binder().len().saturating_sub(1)
153+
})
154+
.unwrap_or(0);
154155

155156
// Account for `foo.bar<T>`;
156-
let sugg_span = method_name.span.with_hi(call_expr.span.hi());
157-
let snippet = self
158-
.tcx
159-
.sess
160-
.source_map()
161-
.span_to_snippet(sugg_span)
162-
.unwrap_or_else(|_| method_name.to_string());
163-
let (suggestion, applicability) = if has_params.unwrap_or_default() {
164-
(format!("{}(...)", snippet), Applicability::HasPlaceholders)
165-
} else {
166-
(format!("{}()", snippet), Applicability::MaybeIncorrect)
167-
};
157+
let sugg_span = call_expr.span.shrink_to_hi();
158+
let (suggestion, applicability) = (
159+
format!("({})", (0..params).map(|_| "_").collect::<Vec<_>>().join(", ")),
160+
if params > 0 { Applicability::HasPlaceholders } else { Applicability::MaybeIncorrect },
161+
);
168162

169-
err.span_suggestion(sugg_span, msg, suggestion, applicability);
163+
err.span_suggestion_verbose(sugg_span, msg, suggestion, applicability);
170164
}
171165

172166
/// Performs method lookup. If lookup is successful, it will return the callee

src/librustc_typeck/check/mod.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -4941,15 +4941,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
49414941
}
49424942
_ => {}
49434943
}
4944-
if let Ok(code) = self.sess().source_map().span_to_snippet(expr.span) {
4945-
err.span_suggestion(
4946-
expr.span,
4947-
&format!("use parentheses to {}", msg),
4948-
format!("{}({})", code, sugg_call),
4949-
applicability,
4950-
);
4951-
return true;
4952-
}
4944+
err.span_suggestion_verbose(
4945+
expr.span.shrink_to_hi(),
4946+
&format!("use parentheses to {}", msg),
4947+
format!("({})", sugg_call),
4948+
applicability,
4949+
);
4950+
return true;
49534951
}
49544952
false
49554953
}

src/librustc_typeck/check/pat.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -753,17 +753,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
753753
res.descr(),
754754
),
755755
);
756-
let (msg, sugg) = match parent_pat {
757-
Some(Pat { kind: hir::PatKind::Struct(..), .. }) => (
758-
"bind the struct field to a different name instead",
759-
format!("{}: other_{}", ident, ident.as_str().to_lowercase()),
760-
),
761-
_ => (
762-
"introduce a new binding instead",
763-
format!("other_{}", ident.as_str().to_lowercase()),
764-
),
756+
match parent_pat {
757+
Some(Pat { kind: hir::PatKind::Struct(..), .. }) => {
758+
e.span_suggestion_verbose(
759+
ident.span.shrink_to_hi(),
760+
"bind the struct field to a different name instead",
761+
format!(": other_{}", ident.as_str().to_lowercase()),
762+
Applicability::HasPlaceholders,
763+
);
764+
}
765+
_ => {
766+
let msg = "introduce a new binding instead";
767+
let sugg = format!("other_{}", ident.as_str().to_lowercase());
768+
e.span_suggestion(ident.span, msg, sugg, Applicability::HasPlaceholders);
769+
}
765770
};
766-
e.span_suggestion(ident.span, msg, sugg, Applicability::HasPlaceholders);
767771
}
768772
}
769773
e.emit();

src/test/ui/error-codes/E0615.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ error[E0615]: attempted to take value of method `method` on type `Foo`
22
--> $DIR/E0615.rs:11:7
33
|
44
LL | f.method;
5-
| ^^^^^^ help: use parentheses to call the method: `method()`
5+
| ^^^^^^
6+
|
7+
help: use parentheses to call the method
8+
|
9+
LL | f.method();
10+
| ^^
611

712
error: aborting due to previous error
813

src/test/ui/extern/extern-types-unsized.stderr

+5-3
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim
22
--> $DIR/extern-types-unsized.rs:22:20
33
|
44
LL | fn assert_sized<T>() { }
5-
| ------------ -- help: consider relaxing the implicit `Sized` restriction: `: ?Sized`
6-
| |
7-
| required by this bound in `assert_sized`
5+
| ------------ - required by this bound in `assert_sized`
86
...
97
LL | assert_sized::<A>();
108
| ^ doesn't have a size known at compile-time
119
|
1210
= help: the trait `std::marker::Sized` is not implemented for `A`
1311
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
12+
help: consider relaxing the implicit `Sized` restriction
13+
|
14+
LL | fn assert_sized<T: ?Sized>() { }
15+
| ^^^^^^^^
1416

1517
error[E0277]: the size for values of type `A` cannot be known at compilation time
1618
--> $DIR/extern-types-unsized.rs:25:5

src/test/ui/implicit-method-bind.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ error[E0615]: attempted to take value of method `abs` on type `i32`
22
--> $DIR/implicit-method-bind.rs:2:20
33
|
44
LL | let _f = 10i32.abs;
5-
| ^^^ help: use parentheses to call the method: `abs()`
5+
| ^^^
6+
|
7+
help: use parentheses to call the method
8+
|
9+
LL | let _f = 10i32.abs();
10+
| ^^
611

712
error: aborting due to previous error
813

src/test/ui/issues/issue-13853-2.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ error[E0615]: attempted to take value of method `get` on type `std::boxed::Box<(
22
--> $DIR/issue-13853-2.rs:5:43
33
|
44
LL | fn foo(res : Box<dyn ResponseHook>) { res.get }
5-
| ^^^ help: use parentheses to call the method: `get()`
5+
| ^^^
6+
|
7+
help: use parentheses to call the method
8+
|
9+
LL | fn foo(res : Box<dyn ResponseHook>) { res.get() }
10+
| ^^
611

712
error: aborting due to previous error
813

src/test/ui/issues/issue-26472.stderr

+6-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ error[E0616]: field `len` of struct `sub::S` is private
22
--> $DIR/issue-26472.rs:11:13
33
|
44
LL | let v = s.len;
5-
| ^^---
6-
| |
7-
| help: a method `len` also exists, call it with parentheses: `len()`
5+
| ^^^^^
6+
|
7+
help: a method `len` also exists, call it with parentheses
8+
|
9+
LL | let v = s.len();
10+
| ^^
811

912
error[E0616]: field `len` of struct `sub::S` is private
1013
--> $DIR/issue-26472.rs:12:5

src/test/ui/issues/issue-35241.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ LL | struct Foo(u32);
55
| ---------------- fn(u32) -> Foo {Foo} defined here
66
LL |
77
LL | fn test() -> Foo { Foo }
8-
| --- ^^^
9-
| | |
10-
| | expected struct `Foo`, found fn item
11-
| | help: use parentheses to instantiate this tuple struct: `Foo(_)`
8+
| --- ^^^ expected struct `Foo`, found fn item
9+
| |
1210
| expected `Foo` because of return type
1311
|
1412
= note: expected struct `Foo`
1513
found fn item `fn(u32) -> Foo {Foo}`
14+
help: use parentheses to instantiate this tuple struct
15+
|
16+
LL | fn test() -> Foo { Foo(_) }
17+
| ^^^
1618

1719
error: aborting due to previous error
1820

src/test/ui/methods/method-missing-call.stderr

+12-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,23 @@ error[E0615]: attempted to take value of method `get_x` on type `Point`
22
--> $DIR/method-missing-call.rs:22:26
33
|
44
LL | .get_x;
5-
| ^^^^^ help: use parentheses to call the method: `get_x()`
5+
| ^^^^^
6+
|
7+
help: use parentheses to call the method
8+
|
9+
LL | .get_x();
10+
| ^^
611

712
error[E0615]: attempted to take value of method `filter_map` on type `std::iter::Filter<std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>`
813
--> $DIR/method-missing-call.rs:29:16
914
|
1015
LL | .filter_map;
11-
| ^^^^^^^^^^ help: use parentheses to call the method: `filter_map(...)`
16+
| ^^^^^^^^^^
17+
|
18+
help: use parentheses to call the method
19+
|
20+
LL | .filter_map(_);
21+
| ^^^
1222

1323
error: aborting due to 2 previous errors
1424

src/test/ui/question-mark-type-infer.stderr

+5-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ error[E0284]: type annotations needed
22
--> $DIR/question-mark-type-infer.rs:12:21
33
|
44
LL | l.iter().map(f).collect()?
5-
| ^^^^^^^
6-
| |
7-
| cannot infer type
8-
| help: consider specifying the type argument in the method call: `collect::<B>`
5+
| ^^^^^^^ cannot infer type
96
|
107
= note: cannot resolve `<_ as std::ops::Try>::Ok == _`
8+
help: consider specifying the type argument in the method call
9+
|
10+
LL | l.iter().map(f).collect::<B>()?
11+
| ^^^^^
1112

1213
error: aborting due to previous error
1314

0 commit comments

Comments
 (0)