mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 10:45:18 +00:00
use structured suggestion for method calls
Furthermore, don't suggest calling the method if it is part of a place expression, as this is invalid syntax.
This commit is contained in:
parent
cae164753f
commit
e3fe0ee97b
@ -11,6 +11,7 @@ pub use self::CandidateSource::*;
|
|||||||
pub use self::suggest::{SelfSource, TraitInfo};
|
pub use self::suggest::{SelfSource, TraitInfo};
|
||||||
|
|
||||||
use check::FnCtxt;
|
use check::FnCtxt;
|
||||||
|
use errors::{Applicability, DiagnosticBuilder};
|
||||||
use namespace::Namespace;
|
use namespace::Namespace;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
@ -123,6 +124,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a suggestion to call the given method to the provided diagnostic.
|
||||||
|
crate fn suggest_method_call(
|
||||||
|
&self,
|
||||||
|
err: &mut DiagnosticBuilder<'a>,
|
||||||
|
msg: &str,
|
||||||
|
method_name: ast::Ident,
|
||||||
|
self_ty: Ty<'tcx>,
|
||||||
|
call_expr_id: ast::NodeId,
|
||||||
|
) {
|
||||||
|
let has_params = self
|
||||||
|
.probe_for_name(
|
||||||
|
method_name.span,
|
||||||
|
probe::Mode::MethodCall,
|
||||||
|
method_name,
|
||||||
|
IsSuggestion(false),
|
||||||
|
self_ty,
|
||||||
|
call_expr_id,
|
||||||
|
ProbeScope::TraitsInScope,
|
||||||
|
)
|
||||||
|
.and_then(|pick| {
|
||||||
|
let sig = self.tcx.fn_sig(pick.item.def_id);
|
||||||
|
Ok(sig.inputs().skip_binder().len() > 1)
|
||||||
|
});
|
||||||
|
|
||||||
|
let (suggestion, applicability) = if has_params.unwrap_or_default() {
|
||||||
|
(
|
||||||
|
format!("{}(...)", method_name),
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(format!("{}()", method_name), Applicability::MaybeIncorrect)
|
||||||
|
};
|
||||||
|
|
||||||
|
err.span_suggestion_with_applicability(method_name.span, msg, suggestion, applicability);
|
||||||
|
}
|
||||||
|
|
||||||
/// Performs method lookup. If lookup is successful, it will return the callee
|
/// Performs method lookup. If lookup is successful, it will return the callee
|
||||||
/// and store an appropriate adjustment for the self-expr. In some cases it may
|
/// and store an appropriate adjustment for the self-expr. In some cases it may
|
||||||
/// report an error (e.g., invoking the `drop` method).
|
/// report an error (e.g., invoking the `drop` method).
|
||||||
|
@ -3412,19 +3412,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
"field `{}` of struct `{}` is private",
|
"field `{}` of struct `{}` is private",
|
||||||
field, struct_path);
|
field, struct_path);
|
||||||
// Also check if an accessible method exists, which is often what is meant.
|
// Also check if an accessible method exists, which is often what is meant.
|
||||||
if self.method_exists(field, expr_t, expr.id, false) {
|
if self.method_exists(field, expr_t, expr.id, false) && !self.expr_in_place(expr.id) {
|
||||||
err.note(&format!("a method `{}` also exists, perhaps you wish to call it", field));
|
self.suggest_method_call(
|
||||||
|
&mut err,
|
||||||
|
&format!("a method `{}` also exists, call it with parentheses", field),
|
||||||
|
field,
|
||||||
|
expr_t,
|
||||||
|
expr.id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
field_ty
|
field_ty
|
||||||
} else if field.name == keywords::Invalid.name() {
|
} else if field.name == keywords::Invalid.name() {
|
||||||
self.tcx().types.err
|
self.tcx().types.err
|
||||||
} else if self.method_exists(field, expr_t, expr.id, true) {
|
} else if self.method_exists(field, expr_t, expr.id, true) {
|
||||||
type_error_struct!(self.tcx().sess, field.span, expr_t, E0615,
|
let mut err = type_error_struct!(self.tcx().sess, field.span, expr_t, E0615,
|
||||||
"attempted to take value of method `{}` on type `{}`",
|
"attempted to take value of method `{}` on type `{}`",
|
||||||
field, expr_t)
|
field, expr_t);
|
||||||
.help("maybe a `()` to call it is missing?")
|
|
||||||
.emit();
|
if !self.expr_in_place(expr.id) {
|
||||||
|
self.suggest_method_call(
|
||||||
|
&mut err,
|
||||||
|
"use parentheses to call the method",
|
||||||
|
field,
|
||||||
|
expr_t,
|
||||||
|
expr.id
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
err.help("methods are immutable and cannot be assigned to");
|
||||||
|
}
|
||||||
|
|
||||||
|
err.emit();
|
||||||
self.tcx().types.err
|
self.tcx().types.err
|
||||||
} else {
|
} else {
|
||||||
if !expr_t.is_primitive_ty() {
|
if !expr_t.is_primitive_ty() {
|
||||||
@ -5435,6 +5453,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
original_values,
|
original_values,
|
||||||
query_result)
|
query_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether an expression is contained inside the LHS of an assignment expression.
|
||||||
|
fn expr_in_place(&self, mut expr_id: ast::NodeId) -> bool {
|
||||||
|
let mut contained_in_place = false;
|
||||||
|
|
||||||
|
while let hir::Node::Expr(parent_expr) =
|
||||||
|
self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
|
||||||
|
{
|
||||||
|
match &parent_expr.node {
|
||||||
|
hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
|
||||||
|
if lhs.id == expr_id {
|
||||||
|
contained_in_place = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
expr_id = parent_expr.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
contained_in_place
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
@ -18,4 +18,5 @@ fn cat(in_x : usize, in_y : isize) -> Cat {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let nyan : Cat = cat(52, 99);
|
let nyan : Cat = cat(52, 99);
|
||||||
nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method
|
nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method
|
||||||
|
nyan.speak += || println!("meow"); //~ ERROR attempted to take value of method
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,16 @@ error[E0615]: attempted to take value of method `speak` on type `Cat`
|
|||||||
LL | nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method
|
LL | nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
= help: maybe a `()` to call it is missing?
|
= help: methods are immutable and cannot be assigned to
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0615]: attempted to take value of method `speak` on type `Cat`
|
||||||
|
--> $DIR/assign-to-method.rs:21:8
|
||||||
|
|
|
||||||
|
LL | nyan.speak += || println!("meow"); //~ ERROR attempted to take value of method
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: methods are immutable and cannot be assigned to
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0615`.
|
For more information about this error, try `rustc --explain E0615`.
|
||||||
|
@ -80,17 +80,13 @@ error[E0615]: attempted to take value of method `collect` on type `std::ops::Ran
|
|||||||
--> $DIR/issue-40396.rs:2:13
|
--> $DIR/issue-40396.rs:2:13
|
||||||
|
|
|
|
||||||
LL | (0..13).collect<Vec<i32>>();
|
LL | (0..13).collect<Vec<i32>>();
|
||||||
| ^^^^^^^
|
| ^^^^^^^ help: use parentheses to call the method: `collect()`
|
||||||
|
|
|
||||||
= help: maybe a `()` to call it is missing?
|
|
||||||
|
|
||||||
error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>`
|
error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>`
|
||||||
--> $DIR/issue-40396.rs:18:13
|
--> $DIR/issue-40396.rs:18:13
|
||||||
|
|
|
|
||||||
LL | (0..13).collect<Vec<i32>();
|
LL | (0..13).collect<Vec<i32>();
|
||||||
| ^^^^^^^
|
| ^^^^^^^ help: use parentheses to call the method: `collect()`
|
||||||
|
|
|
||||||
= help: maybe a `()` to call it is missing?
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-40396.rs:18:29
|
--> $DIR/issue-40396.rs:18:29
|
||||||
|
@ -2,9 +2,7 @@ error[E0615]: attempted to take value of method `method` on type `Foo`
|
|||||||
--> $DIR/E0615.rs:11:7
|
--> $DIR/E0615.rs:11:7
|
||||||
|
|
|
|
||||||
LL | f.method; //~ ERROR E0615
|
LL | f.method; //~ ERROR E0615
|
||||||
| ^^^^^^
|
| ^^^^^^ help: use parentheses to call the method: `method()`
|
||||||
|
|
|
||||||
= help: maybe a `()` to call it is missing?
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -2,9 +2,7 @@ error[E0615]: attempted to take value of method `abs` on type `i32`
|
|||||||
--> $DIR/implicit-method-bind.rs:2:20
|
--> $DIR/implicit-method-bind.rs:2:20
|
||||||
|
|
|
|
||||||
LL | let _f = 10i32.abs; //~ ERROR attempted to take value of method
|
LL | let _f = 10i32.abs; //~ ERROR attempted to take value of method
|
||||||
| ^^^
|
| ^^^ help: use parentheses to call the method: `abs()`
|
||||||
|
|
|
||||||
= help: maybe a `()` to call it is missing?
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -2,9 +2,7 @@ error[E0615]: attempted to take value of method `get` on type `std::boxed::Box<(
|
|||||||
--> $DIR/issue-13853-2.rs:5:39
|
--> $DIR/issue-13853-2.rs:5:39
|
||||||
|
|
|
|
||||||
LL | fn foo(res : Box<ResponseHook>) { res.get } //~ ERROR attempted to take value of method
|
LL | fn foo(res : Box<ResponseHook>) { res.get } //~ ERROR attempted to take value of method
|
||||||
| ^^^
|
| ^^^ help: use parentheses to call the method: `get()`
|
||||||
|
|
|
||||||
= help: maybe a `()` to call it is missing?
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -8,6 +8,6 @@ mod sub {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let s = sub::S::new();
|
let s = sub::S::new();
|
||||||
let v = s.len;
|
let v = s.len; //~ ERROR field `len` of struct `sub::S` is private
|
||||||
//~^ ERROR field `len` of struct `sub::S` is private
|
s.len = v; //~ ERROR field `len` of struct `sub::S` is private
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
error[E0616]: field `len` of struct `sub::S` is private
|
error[E0616]: field `len` of struct `sub::S` is private
|
||||||
--> $DIR/issue-26472.rs:11:13
|
--> $DIR/issue-26472.rs:11:13
|
||||||
|
|
|
|
||||||
LL | let v = s.len;
|
LL | let v = s.len; //~ ERROR field `len` of struct `sub::S` is private
|
||||||
| ^^^^^
|
| ^^---
|
||||||
|
|
| |
|
||||||
= note: a method `len` also exists, perhaps you wish to call it
|
| help: a method `len` also exists, call it with parentheses: `len()`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0616]: field `len` of struct `sub::S` is private
|
||||||
|
--> $DIR/issue-26472.rs:12:5
|
||||||
|
|
|
||||||
|
LL | s.len = v; //~ ERROR field `len` of struct `sub::S` is private
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0616`.
|
For more information about this error, try `rustc --explain E0616`.
|
||||||
|
@ -2,17 +2,13 @@ error[E0615]: attempted to take value of method `get_x` on type `Point`
|
|||||||
--> $DIR/method-missing-call.rs:22:26
|
--> $DIR/method-missing-call.rs:22:26
|
||||||
|
|
|
|
||||||
LL | .get_x;//~ ERROR attempted to take value of method `get_x` on type `Point`
|
LL | .get_x;//~ ERROR attempted to take value of method `get_x` on type `Point`
|
||||||
| ^^^^^
|
| ^^^^^ help: use parentheses to call the method: `get_x()`
|
||||||
|
|
|
||||||
= help: maybe a `()` to call it is missing?
|
|
||||||
|
|
||||||
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]>`
|
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]>`
|
||||||
--> $DIR/method-missing-call.rs:29:16
|
--> $DIR/method-missing-call.rs:29:16
|
||||||
|
|
|
|
||||||
LL | .filter_map; //~ ERROR attempted to take value of method `filter_map` on type
|
LL | .filter_map; //~ ERROR attempted to take value of method `filter_map` on type
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^ help: use parentheses to call the method: `filter_map(...)`
|
||||||
|
|
|
||||||
= help: maybe a `()` to call it is missing?
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -16,5 +16,6 @@ fn main() {
|
|||||||
//~| SUGGESTION principal
|
//~| SUGGESTION principal
|
||||||
|
|
||||||
let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U`
|
let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U`
|
||||||
//~| HELP maybe a `()` to call it is missing
|
//~| HELP use parentheses to call the method
|
||||||
|
//~| SUGGESTION calculate()
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,7 @@ error[E0615]: attempted to take value of method `calculate` on type `U`
|
|||||||
--> $DIR/union-suggest-field.rs:18:15
|
--> $DIR/union-suggest-field.rs:18:15
|
||||||
|
|
|
|
||||||
LL | let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U`
|
LL | let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U`
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^ help: use parentheses to call the method: `calculate()`
|
||||||
|
|
|
||||||
= help: maybe a `()` to call it is missing?
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user