about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/session/mod.rs5
-rw-r--r--src/librustc_resolve/lib.rs59
-rw-r--r--src/librustc_typeck/astconv.rs57
-rw-r--r--src/librustc_typeck/check/method/suggest.rs18
-rw-r--r--src/test/ui/issues/issue-22933-3.stderr4
-rw-r--r--src/test/ui/suggestions/suggest-std-when-using-type.rs7
-rw-r--r--src/test/ui/suggestions/suggest-std-when-using-type.stderr24
7 files changed, 134 insertions, 40 deletions
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index eed516a4381..d9da9950373 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -165,6 +165,10 @@ pub struct Session {
 
     /// `Span`s of trait methods that weren't found to avoid emitting object safety errors
     pub trait_methods_not_found: Lock<FxHashSet<Span>>,
+
+    /// Mapping from ident span to path span for paths that don't exist as written, but that
+    /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
+    pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>,
 }
 
 pub struct PerfStats {
@@ -1248,6 +1252,7 @@ fn build_session_(
         has_panic_handler: Once::new(),
         driver_lint_caps,
         trait_methods_not_found: Lock::new(Default::default()),
+        confused_type_with_std_module: Lock::new(Default::default()),
     };
 
     validate_commandline_args_with_session_available(&sess);
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 08b2f1a0f16..8df83120738 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -3273,6 +3273,25 @@ impl<'a> Resolver<'a> {
                     let traits = self.get_traits_containing_item(item_name, ns);
                     self.trait_map.insert(id, traits);
                 }
+
+                let mut std_path = vec![Segment::from_ident(Ident::from_str("std"))];
+                std_path.extend(path);
+                if self.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) {
+                    let cl = CrateLint::No;
+                    let ns = Some(ns);
+                    if let PathResult::Module(_) | PathResult::NonModule(_) =
+                        self.resolve_path_without_parent_scope(&std_path, ns, false, span, cl)
+                    {
+                        // check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
+                        let item_span = path.iter().last().map(|segment| segment.ident.span)
+                            .unwrap_or(span);
+                        debug!("accessed item from `std` submodule as a bare type {:?}", std_path);
+                        let mut hm = self.session.confused_type_with_std_module.borrow_mut();
+                        hm.insert(item_span, span);
+                        // In some places (E0223) we only have access to the full path
+                        hm.insert(span, span);
+                    }
+                }
                 resolution
             }
             _ => report_errors(self, None)
@@ -3387,16 +3406,17 @@ impl<'a> Resolver<'a> {
     }
 
     // Resolve in alternative namespaces if resolution in the primary namespace fails.
-    fn resolve_qpath_anywhere(&mut self,
-                              id: NodeId,
-                              qself: Option<&QSelf>,
-                              path: &[Segment],
-                              primary_ns: Namespace,
-                              span: Span,
-                              defer_to_typeck: bool,
-                              global_by_default: bool,
-                              crate_lint: CrateLint)
-                              -> Option<PathResolution> {
+    fn resolve_qpath_anywhere(
+        &mut self,
+        id: NodeId,
+        qself: Option<&QSelf>,
+        path: &[Segment],
+        primary_ns: Namespace,
+        span: Span,
+        defer_to_typeck: bool,
+        global_by_default: bool,
+        crate_lint: CrateLint,
+    ) -> Option<PathResolution> {
         let mut fin_res = None;
         // FIXME: can't resolve paths in macro namespace yet, macros are
         // processed by the little special hack below.
@@ -3426,15 +3446,16 @@ impl<'a> Resolver<'a> {
     }
 
     /// Handles paths that may refer to associated items.
-    fn resolve_qpath(&mut self,
-                     id: NodeId,
-                     qself: Option<&QSelf>,
-                     path: &[Segment],
-                     ns: Namespace,
-                     span: Span,
-                     global_by_default: bool,
-                     crate_lint: CrateLint)
-                     -> Option<PathResolution> {
+    fn resolve_qpath(
+        &mut self,
+        id: NodeId,
+        qself: Option<&QSelf>,
+        path: &[Segment],
+        ns: Namespace,
+        span: Span,
+        global_by_default: bool,
+        crate_lint: CrateLint,
+    ) -> Option<PathResolution> {
         debug!(
             "resolve_qpath(id={:?}, qself={:?}, path={:?}, \
              ns={:?}, span={:?}, global_by_default={:?})",
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 0c206b27f80..be8e5dae1d9 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1187,18 +1187,33 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         ty
     }
 
-    fn report_ambiguous_associated_type(&self,
-                                        span: Span,
-                                        type_str: &str,
-                                        trait_str: &str,
-                                        name: &str) {
-        struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type")
-            .span_suggestion(
+    fn report_ambiguous_associated_type(
+        &self,
+        span: Span,
+        type_str: &str,
+        trait_str: &str,
+        name: &str,
+    ) {
+        let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
+        if let (Some(_), Ok(snippet)) = (
+            self.tcx().sess.confused_type_with_std_module.borrow().get(&span),
+            self.tcx().sess.source_map().span_to_snippet(span),
+         ) {
+            err.span_suggestion(
                 span,
-                "use fully-qualified syntax",
-                format!("<{} as {}>::{}", type_str, trait_str, name),
-                Applicability::HasPlaceholders
-            ).emit();
+                "you are looking for the module in `std`, not the primitive type",
+                format!("std::{}", snippet),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            err.span_suggestion(
+                    span,
+                    "use fully-qualified syntax",
+                    format!("<{} as {}>::{}", type_str, trait_str, name),
+                    Applicability::HasPlaceholders
+            );
+        }
+        err.emit();
     }
 
     // Search for a bound on a type parameter which includes the associated item
@@ -1391,10 +1406,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     err.emit();
                 } else if !qself_ty.references_error() {
                     // Don't print `TyErr` to the user.
-                    self.report_ambiguous_associated_type(span,
-                                                          &qself_ty.to_string(),
-                                                          "Trait",
-                                                          &assoc_ident.as_str());
+                    self.report_ambiguous_associated_type(
+                        span,
+                        &qself_ty.to_string(),
+                        "Trait",
+                        &assoc_ident.as_str(),
+                    );
                 }
                 return (tcx.types.err, Def::Err);
             }
@@ -1461,10 +1478,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             ty
         } else {
             let path_str = tcx.def_path_str(trait_def_id);
-            self.report_ambiguous_associated_type(span,
-                                                  "Type",
-                                                  &path_str,
-                                                  &item_segment.ident.as_str());
+            self.report_ambiguous_associated_type(
+                span,
+                "Type",
+                &path_str,
+                &item_segment.ident.as_str(),
+            );
             return tcx.types.err;
         };
 
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index ff889c89770..7121b06e27a 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -292,7 +292,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         return;
                     } else {
                         span = item_name.span;
-                        struct_span_err!(
+                        let mut err = struct_span_err!(
                             tcx.sess,
                             span,
                             E0599,
@@ -300,7 +300,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             item_kind,
                             item_name,
                             ty_str
-                        )
+                        );
+                        if let Some(span) = tcx.sess.confused_type_with_std_module.borrow()
+                            .get(&span)
+                        {
+                            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
+                                err.span_suggestion(
+                                    *span,
+                                    "you are looking for the module in `std`, \
+                                     not the primitive type",
+                                    format!("std::{}", snippet),
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
+                        err
                     }
                 } else {
                     tcx.sess.diagnostic().struct_dummy()
diff --git a/src/test/ui/issues/issue-22933-3.stderr b/src/test/ui/issues/issue-22933-3.stderr
index b1afda6d151..e0e8b5e18a4 100644
--- a/src/test/ui/issues/issue-22933-3.stderr
+++ b/src/test/ui/issues/issue-22933-3.stderr
@@ -3,6 +3,10 @@ error[E0599]: no associated item named `MIN` found for type `u8` in the current
    |
 LL | const FOO: [u32; u8::MIN as usize] = [];
    |                      ^^^ associated item not found in `u8`
+help: you are looking for the module in `std`, not the primitive type
+   |
+LL | const FOO: [u32; std::u8::MIN as usize] = [];
+   |                  ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/suggest-std-when-using-type.rs b/src/test/ui/suggestions/suggest-std-when-using-type.rs
new file mode 100644
index 00000000000..9ca68a635da
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-std-when-using-type.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let pi = f32::consts::PI; //~ ERROR ambiguous associated type
+    let bytes = "hello world".as_bytes();
+    let string = unsafe {
+        str::from_utf8(bytes) //~ ERROR no function or associated item named `from_utf8` found
+    };
+}
diff --git a/src/test/ui/suggestions/suggest-std-when-using-type.stderr b/src/test/ui/suggestions/suggest-std-when-using-type.stderr
new file mode 100644
index 00000000000..eecb4e60f9d
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-std-when-using-type.stderr
@@ -0,0 +1,24 @@
+error[E0223]: ambiguous associated type
+  --> $DIR/suggest-std-when-using-type.rs:2:14
+   |
+LL |     let pi = f32::consts::PI;
+   |              ^^^^^^^^^^^^^^^
+help: you are looking for the module in `std`, not the primitive type
+   |
+LL |     let pi = std::f32::consts::PI;
+   |              ^^^^^^^^^^^^^^^^^^^^
+
+error[E0599]: no function or associated item named `from_utf8` found for type `str` in the current scope
+  --> $DIR/suggest-std-when-using-type.rs:5:14
+   |
+LL |         str::from_utf8(bytes)
+   |              ^^^^^^^^^ function or associated item not found in `str`
+help: you are looking for the module in `std`, not the primitive type
+   |
+LL |         std::str::from_utf8(bytes)
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0223, E0599.
+For more information about an error, try `rustc --explain E0223`.