]> git.lizzy.rs Git - rust.git/commitdiff
fix #101749, use . instead of :: when accessing a method of an object
authoryukang <moorekang@gmail.com>
Sun, 18 Sep 2022 07:35:21 +0000 (15:35 +0800)
committeryukang <moorekang@gmail.com>
Sat, 3 Dec 2022 14:41:12 +0000 (22:41 +0800)
15 files changed:
compiler/rustc_errors/src/lib.rs
compiler/rustc_hir_typeck/src/expr.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/late.rs
src/test/ui/resolve/bad-module.stderr
src/test/ui/resolve/issue-101749-2.rs [new file with mode: 0644]
src/test/ui/resolve/issue-101749-2.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-101749.fixed [new file with mode: 0644]
src/test/ui/resolve/issue-101749.rs [new file with mode: 0644]
src/test/ui/resolve/issue-101749.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-24968.stderr
src/test/ui/resolve/typo-suggestion-mistyped-in-path.stderr
src/test/ui/resolve/use_suggestion.stderr
src/test/ui/suggestions/crate-or-module-typo.stderr

index f8747386c0498d3916ddbc65be287b46d799951a..649165f55572c680556a94eb24c6e3f023206ac1 100644 (file)
@@ -470,6 +470,7 @@ pub enum StashKey {
     /// Maybe there was a typo where a comma was forgotten before
     /// FRU syntax
     MaybeFruTypo,
+    CallAssocMethod,
 }
 
 fn default_track_diagnostic(_: &Diagnostic) {}
index de30bfe6923a7cc84cf77d72c33f2dff50ec2225..c873b0cd08f1dfe726140abd4eac3e00b3589054 100644 (file)
@@ -528,6 +528,7 @@ pub(crate) fn check_expr_path(
             self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span);
         let ty = match res {
             Res::Err => {
+                self.suggest_assoc_method_call(segs);
                 let e =
                     self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
index d0ea2b0e66475df861048ba32899c0e81cbaa0c3..3549a48250ff39b41043bd667ddc8b80647b43bf 100644 (file)
@@ -5,6 +5,7 @@
 use crate::FnCtxt;
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::StashKey;
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
     MultiSpan,
@@ -13,6 +14,8 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::PatKind::Binding;
+use rustc_hir::PathSegment;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::{
     type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
     FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
 };
 
-use std::cmp::Ordering;
-use std::iter;
-
 use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
 use super::{CandidateSource, MethodError, NoMatchData};
+use rustc_hir::intravisit::Visitor;
+use std::cmp::Ordering;
+use std::iter;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@@ -1470,6 +1473,61 @@ fn suggest_constraining_numerical_ty(
         false
     }
 
+    /// For code `rect::area(...)`,
+    /// if `rect` is a local variable and `area` is a valid assoc method for it,
+    /// we try to suggest `rect.area()`
+    pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) {
+        debug!("suggest_assoc_method_call segs: {:?}", segs);
+        let [seg1, seg2] = segs else { return; };
+        let Some(mut diag) =
+                self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
+                else { return };
+
+        let map = self.infcx.tcx.hir();
+        let body = map.body(rustc_hir::BodyId { hir_id: self.body_id });
+        struct LetVisitor<'a> {
+            result: Option<&'a hir::Expr<'a>>,
+            ident_name: Symbol,
+        }
+
+        impl<'v> Visitor<'v> for LetVisitor<'v> {
+            fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
+                if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind {
+                    if let Binding(_, _, ident, ..) = pat.kind &&
+                        ident.name == self.ident_name {
+                        self.result = *init;
+                    }
+                }
+                hir::intravisit::walk_stmt(self, ex);
+            }
+        }
+
+        let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
+        visitor.visit_body(&body);
+
+        let parent = self.tcx.hir().get_parent_node(seg1.hir_id);
+        if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
+            let Some(expr) = visitor.result {
+            let self_ty = self.node_ty(expr.hir_id);
+            let probe = self.lookup_probe(
+                seg2.ident,
+                self_ty,
+                call_expr,
+                ProbeScope::TraitsInScope,
+            );
+            if probe.is_ok() {
+                let sm = self.infcx.tcx.sess.source_map();
+                diag.span_suggestion_verbose(
+                    sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(),
+                    "you may have meant to call an instance method",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect
+                );
+            }
+        }
+        diag.emit();
+    }
+
     /// Suggest calling a method on a field i.e. `a.field.bar()` instead of `a.bar()`
     fn suggest_calling_method_on_field(
         &self,
index bc3a710e84bd046b9213e2086f850d30f47236e8..f6b6cf3a94c18e93f3075ae246db451067694c35 100644 (file)
@@ -1840,13 +1840,16 @@ pub(crate) fn report_path_resolution_error(
 
             (format!("use of undeclared type `{}`", ident), suggestion)
         } else {
-            let suggestion = if ident.name == sym::alloc {
-                Some((
+            let mut suggestion = None;
+            if ident.name == sym::alloc {
+                suggestion = Some((
                     vec![],
                     String::from("add `extern crate alloc` to use the `alloc` crate"),
                     Applicability::MaybeIncorrect,
                 ))
-            } else {
+            }
+
+            suggestion = suggestion.or_else(|| {
                 self.find_similarly_named_module_or_crate(ident.name, &parent_scope.module).map(
                     |sugg| {
                         (
@@ -1856,7 +1859,7 @@ pub(crate) fn report_path_resolution_error(
                         )
                     },
                 )
-            };
+            });
             (format!("use of undeclared crate or module `{}`", ident), suggestion)
         }
     }
index 5072d2aad1669ff99e10c879563db2606aa237a8..107987c2673f7f42b0943c497c34eeba8b6544c1 100644 (file)
@@ -3364,13 +3364,13 @@ fn smart_resolve_path_fragment(
             // Before we start looking for candidates, we have to get our hands
             // on the type user is trying to perform invocation on; basically:
             // we're transforming `HashMap::new` into just `HashMap`.
-            let path = match path.split_last() {
+            let prefix_path = match path.split_last() {
                 Some((_, path)) if !path.is_empty() => path,
                 _ => return Some(parent_err),
             };
 
             let (mut err, candidates) =
-                this.smart_resolve_report_errors(path, path_span, PathSource::Type, None);
+                this.smart_resolve_report_errors(prefix_path, path_span, PathSource::Type, None);
 
             // There are two different error messages user might receive at
             // this point:
@@ -3414,11 +3414,23 @@ fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) {
 
             if this.should_report_errs() {
                 if candidates.is_empty() {
-                    // When there is no suggested imports, we can just emit the error
-                    // and suggestions immediately. Note that we bypass the usually error
-                    // reporting routine (ie via `self.r.report_error`) because we need
-                    // to post-process the `ResolutionError` above.
-                    err.emit();
+                    if path.len() == 2 && prefix_path.len() == 1 {
+                        // Delay to check whether methond name is an associated function or not
+                        // ```
+                        // let foo = Foo {};
+                        // foo::bar(); // possibly suggest to foo.bar();
+                        //```
+                        err.stash(
+                            prefix_path[0].ident.span,
+                            rustc_errors::StashKey::CallAssocMethod,
+                        );
+                    } else {
+                        // When there is no suggested imports, we can just emit the error
+                        // and suggestions immediately. Note that we bypass the usually error
+                        // reporting routine (ie via `self.r.report_error`) because we need
+                        // to post-process the `ResolutionError` above.
+                        err.emit();
+                    }
                 } else {
                     // If there are suggested imports, the error reporting is delayed
                     this.r.use_injections.push(UseError {
@@ -3427,7 +3439,7 @@ fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) {
                         def_id,
                         instead: false,
                         suggestion: None,
-                        path: path.into(),
+                        path: prefix_path.into(),
                         is_call: source.is_call(),
                     });
                 }
index 581a6619814601a24250cb80b383d82121a0ba7f..558760c6793ab08dc34bdde3589725466ba53d91 100644 (file)
@@ -1,15 +1,15 @@
-error[E0433]: failed to resolve: use of undeclared crate or module `thing`
-  --> $DIR/bad-module.rs:2:15
-   |
-LL |     let foo = thing::len(Vec::new());
-   |               ^^^^^ use of undeclared crate or module `thing`
-
 error[E0433]: failed to resolve: use of undeclared crate or module `foo`
   --> $DIR/bad-module.rs:5:15
    |
 LL |     let foo = foo::bar::baz();
    |               ^^^ use of undeclared crate or module `foo`
 
+error[E0433]: failed to resolve: use of undeclared crate or module `thing`
+  --> $DIR/bad-module.rs:2:15
+   |
+LL |     let foo = thing::len(Vec::new());
+   |               ^^^^^ use of undeclared crate or module `thing`
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/resolve/issue-101749-2.rs b/src/test/ui/resolve/issue-101749-2.rs
new file mode 100644 (file)
index 0000000..4d3d469
--- /dev/null
@@ -0,0 +1,16 @@
+struct Rectangle {
+    width: i32,
+    height: i32,
+}
+impl Rectangle {
+    fn new(width: i32, height: i32) -> Self {
+        Self { width, height }
+    }
+}
+
+fn main() {
+    let rect = Rectangle::new(3, 4);
+    // `area` is not implemented for `Rectangle`, so this should not suggest
+    let _ = rect::area();
+    //~^ ERROR failed to resolve: use of undeclared crate or module `rect`
+}
diff --git a/src/test/ui/resolve/issue-101749-2.stderr b/src/test/ui/resolve/issue-101749-2.stderr
new file mode 100644 (file)
index 0000000..370d4b1
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: use of undeclared crate or module `rect`
+  --> $DIR/issue-101749-2.rs:14:13
+   |
+LL |     let _ = rect::area();
+   |             ^^^^ use of undeclared crate or module `rect`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/resolve/issue-101749.fixed b/src/test/ui/resolve/issue-101749.fixed
new file mode 100644 (file)
index 0000000..3e55442
--- /dev/null
@@ -0,0 +1,19 @@
+// run-rustfix
+struct Rectangle {
+    width: i32,
+    height: i32,
+}
+impl Rectangle {
+    fn new(width: i32, height: i32) -> Self {
+        Self { width, height }
+    }
+    fn area(&self) -> i32 {
+        self.height * self.width
+    }
+}
+
+fn main() {
+    let rect = Rectangle::new(3, 4);
+    let _ = rect.area();
+    //~^ ERROR failed to resolve: use of undeclared crate or module `rect`
+}
diff --git a/src/test/ui/resolve/issue-101749.rs b/src/test/ui/resolve/issue-101749.rs
new file mode 100644 (file)
index 0000000..fd67cca
--- /dev/null
@@ -0,0 +1,19 @@
+// run-rustfix
+struct Rectangle {
+    width: i32,
+    height: i32,
+}
+impl Rectangle {
+    fn new(width: i32, height: i32) -> Self {
+        Self { width, height }
+    }
+    fn area(&self) -> i32 {
+        self.height * self.width
+    }
+}
+
+fn main() {
+    let rect = Rectangle::new(3, 4);
+    let _ = rect::area();
+    //~^ ERROR failed to resolve: use of undeclared crate or module `rect`
+}
diff --git a/src/test/ui/resolve/issue-101749.stderr b/src/test/ui/resolve/issue-101749.stderr
new file mode 100644 (file)
index 0000000..dd29d7f
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0433]: failed to resolve: use of undeclared crate or module `rect`
+  --> $DIR/issue-101749.rs:17:13
+   |
+LL |     let _ = rect::area();
+   |             ^^^^ use of undeclared crate or module `rect`
+   |
+help: you may have meant to call an instance method
+   |
+LL |     let _ = rect.area();
+   |                 ~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
index 7e539d258048e03989eb25fa94c9fbfac73baada..82f5a1d5b57b3a167741b4600fe18a6dc9486846 100644 (file)
@@ -1,15 +1,3 @@
-error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
-  --> $DIR/issue-24968.rs:21:19
-   |
-LL | const FOO2: u32 = Self::bar();
-   |                   ^^^^ `Self` is only available in impls, traits, and type definitions
-
-error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
-  --> $DIR/issue-24968.rs:27:22
-   |
-LL | static FOO_S2: u32 = Self::bar();
-   |                      ^^^^ `Self` is only available in impls, traits, and type definitions
-
 error[E0411]: cannot find type `Self` in this scope
   --> $DIR/issue-24968.rs:3:11
    |
@@ -51,6 +39,18 @@ LL | static FOO_S: Self = 0;
    |        |
    |        `Self` not allowed in a static item
 
+error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
+  --> $DIR/issue-24968.rs:21:19
+   |
+LL | const FOO2: u32 = Self::bar();
+   |                   ^^^^ `Self` is only available in impls, traits, and type definitions
+
+error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
+  --> $DIR/issue-24968.rs:27:22
+   |
+LL | static FOO_S2: u32 = Self::bar();
+   |                      ^^^^ `Self` is only available in impls, traits, and type definitions
+
 error: aborting due to 7 previous errors
 
 Some errors have detailed explanations: E0411, E0433.
index ff7cf531c06dd9bbedf494cb9b1786c0c00348ea..89b69e1409967544f917a7bb296e3843210dc5e0 100644 (file)
@@ -1,3 +1,24 @@
+error[E0433]: failed to resolve: could not find `Struc` in `module`
+  --> $DIR/typo-suggestion-mistyped-in-path.rs:35:13
+   |
+LL |     module::Struc::foo();
+   |             ^^^^^
+   |             |
+   |             could not find `Struc` in `module`
+   |             help: a struct with a similar name exists: `Struct`
+
+error[E0599]: no function or associated item named `fob` found for struct `Struct` in the current scope
+  --> $DIR/typo-suggestion-mistyped-in-path.rs:23:13
+   |
+LL | struct Struct;
+   | ------------- function or associated item `fob` not found for this struct
+...
+LL |     Struct::fob();
+   |             ^^^
+   |             |
+   |             function or associated item not found in `Struct`
+   |             help: there is an associated function with a similar name: `foo`
+
 error[E0433]: failed to resolve: use of undeclared type `Struc`
   --> $DIR/typo-suggestion-mistyped-in-path.rs:27:5
    |
@@ -18,15 +39,6 @@ help: there is a crate or module with a similar name
 LL |     module::foo();
    |     ~~~~~~
 
-error[E0433]: failed to resolve: could not find `Struc` in `module`
-  --> $DIR/typo-suggestion-mistyped-in-path.rs:35:13
-   |
-LL |     module::Struc::foo();
-   |             ^^^^^
-   |             |
-   |             could not find `Struc` in `module`
-   |             help: a struct with a similar name exists: `Struct`
-
 error[E0433]: failed to resolve: use of undeclared type `Trai`
   --> $DIR/typo-suggestion-mistyped-in-path.rs:39:5
    |
@@ -36,18 +48,6 @@ LL |     Trai::foo();
    |     use of undeclared type `Trai`
    |     help: a trait with a similar name exists: `Trait`
 
-error[E0599]: no function or associated item named `fob` found for struct `Struct` in the current scope
-  --> $DIR/typo-suggestion-mistyped-in-path.rs:23:13
-   |
-LL | struct Struct;
-   | ------------- function or associated item `fob` not found for this struct
-...
-LL |     Struct::fob();
-   |             ^^^
-   |             |
-   |             function or associated item not found in `Struct`
-   |             help: there is an associated function with a similar name: `foo`
-
 error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0433, E0599.
index 58cb659e822035b2bf4fcba5f1cea7f74f7de426..54ad853831f368bbf1dcba37ee673abfd8cec7d4 100644 (file)
@@ -1,9 +1,3 @@
-error[E0433]: failed to resolve: use of undeclared type `GooMap`
-  --> $DIR/use_suggestion.rs:3:14
-   |
-LL |     let x2 = GooMap::new();
-   |              ^^^^^^ use of undeclared type `GooMap`
-
 error[E0433]: failed to resolve: use of undeclared type `HashMap`
   --> $DIR/use_suggestion.rs:2:14
    |
@@ -32,6 +26,12 @@ error[E0412]: cannot find type `GooMap` in this scope
 LL |     let y2: GooMap;
    |             ^^^^^^ not found in this scope
 
+error[E0433]: failed to resolve: use of undeclared type `GooMap`
+  --> $DIR/use_suggestion.rs:3:14
+   |
+LL |     let x2 = GooMap::new();
+   |              ^^^^^^ use of undeclared type `GooMap`
+
 error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0412, E0433.
index e8250c9fa5ff49971a87e91409bdb89320602937..98b88b4fb9202cc7d5ccbe50e6f81e3278dad298 100644 (file)
@@ -20,12 +20,6 @@ help: there is a crate or module with a similar name
 LL | use bar::bar;
    |     ~~~
 
-error[E0433]: failed to resolve: use of undeclared crate or module `bar`
-  --> $DIR/crate-or-module-typo.rs:6:20
-   |
-LL |     pub fn bar() { bar::baz(); }
-   |                    ^^^ use of undeclared crate or module `bar`
-
 error[E0433]: failed to resolve: use of undeclared crate or module `st`
   --> $DIR/crate-or-module-typo.rs:14:10
    |
@@ -37,6 +31,12 @@ help: there is a crate or module with a similar name
 LL |     bar: std::cell::Cell<bool>
    |          ~~~
 
+error[E0433]: failed to resolve: use of undeclared crate or module `bar`
+  --> $DIR/crate-or-module-typo.rs:6:20
+   |
+LL |     pub fn bar() { bar::baz(); }
+   |                    ^^^ use of undeclared crate or module `bar`
+
 error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0432, E0433.