mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +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};
|
||||
|
||||
use check::FnCtxt;
|
||||
use errors::{Applicability, DiagnosticBuilder};
|
||||
use namespace::Namespace;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
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
|
||||
/// and store an appropriate adjustment for the self-expr. In some cases it may
|
||||
/// 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, struct_path);
|
||||
// Also check if an accessible method exists, which is often what is meant.
|
||||
if self.method_exists(field, expr_t, expr.id, false) {
|
||||
err.note(&format!("a method `{}` also exists, perhaps you wish to call it", field));
|
||||
if self.method_exists(field, expr_t, expr.id, false) && !self.expr_in_place(expr.id) {
|
||||
self.suggest_method_call(
|
||||
&mut err,
|
||||
&format!("a method `{}` also exists, call it with parentheses", field),
|
||||
field,
|
||||
expr_t,
|
||||
expr.id,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
field_ty
|
||||
} else if field.name == keywords::Invalid.name() {
|
||||
self.tcx().types.err
|
||||
} 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 `{}`",
|
||||
field, expr_t)
|
||||
.help("maybe a `()` to call it is missing?")
|
||||
.emit();
|
||||
field, expr_t);
|
||||
|
||||
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
|
||||
} else {
|
||||
if !expr_t.is_primitive_ty() {
|
||||
@ -5435,6 +5453,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
original_values,
|
||||
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>,
|
||||
|
@ -18,4 +18,5 @@ fn cat(in_x : usize, in_y : isize) -> Cat {
|
||||
fn main() {
|
||||
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
|
||||
}
|
||||
|
@ -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
|
||||
| ^^^^^
|
||||
|
|
||||
= 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`.
|
||||
|
@ -80,17 +80,13 @@ error[E0615]: attempted to take value of method `collect` on type `std::ops::Ran
|
||||
--> $DIR/issue-40396.rs:2:13
|
||||
|
|
||||
LL | (0..13).collect<Vec<i32>>();
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: maybe a `()` to call it is missing?
|
||||
| ^^^^^^^ help: use parentheses to call the method: `collect()`
|
||||
|
||||
error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>`
|
||||
--> $DIR/issue-40396.rs:18:13
|
||||
|
|
||||
LL | (0..13).collect<Vec<i32>();
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: maybe a `()` to call it is missing?
|
||||
| ^^^^^^^ help: use parentheses to call the method: `collect()`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $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
|
||||
|
|
||||
LL | f.method; //~ ERROR E0615
|
||||
| ^^^^^^
|
||||
|
|
||||
= help: maybe a `()` to call it is missing?
|
||||
| ^^^^^^ help: use parentheses to call the method: `method()`
|
||||
|
||||
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
|
||||
|
|
||||
LL | let _f = 10i32.abs; //~ ERROR attempted to take value of method
|
||||
| ^^^
|
||||
|
|
||||
= help: maybe a `()` to call it is missing?
|
||||
| ^^^ help: use parentheses to call the method: `abs()`
|
||||
|
||||
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
|
||||
|
|
||||
LL | fn foo(res : Box<ResponseHook>) { res.get } //~ ERROR attempted to take value of method
|
||||
| ^^^
|
||||
|
|
||||
= help: maybe a `()` to call it is missing?
|
||||
| ^^^ help: use parentheses to call the method: `get()`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -8,6 +8,6 @@ mod sub {
|
||||
|
||||
fn main() {
|
||||
let s = sub::S::new();
|
||||
let v = s.len;
|
||||
//~^ ERROR field `len` of struct `sub::S` is private
|
||||
let v = s.len; //~ 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
|
||||
--> $DIR/issue-26472.rs:11:13
|
||||
|
|
||||
LL | let v = s.len;
|
||||
| ^^^^^
|
||||
|
|
||||
= note: a method `len` also exists, perhaps you wish to call it
|
||||
LL | let v = s.len; //~ ERROR field `len` of struct `sub::S` is private
|
||||
| ^^---
|
||||
| |
|
||||
| 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`.
|
||||
|
@ -2,17 +2,13 @@ error[E0615]: attempted to take value of method `get_x` on type `Point`
|
||||
--> $DIR/method-missing-call.rs:22:26
|
||||
|
|
||||
LL | .get_x;//~ ERROR attempted to take value of method `get_x` on type `Point`
|
||||
| ^^^^^
|
||||
|
|
||||
= help: maybe a `()` to call it is missing?
|
||||
| ^^^^^ help: use parentheses to call the method: `get_x()`
|
||||
|
||||
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
|
||||
|
|
||||
LL | .filter_map; //~ ERROR attempted to take value of method `filter_map` on type
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: maybe a `()` to call it is missing?
|
||||
| ^^^^^^^^^^ help: use parentheses to call the method: `filter_map(...)`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -16,5 +16,6 @@ fn main() {
|
||||
//~| SUGGESTION principal
|
||||
|
||||
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
|
||||
|
|
||||
LL | 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: `calculate()`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user