about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2018-10-02 22:54:29 +0200
committerGitHub <noreply@github.com>2018-10-02 22:54:29 +0200
commitf70f6ec56751e5095830fd93d0607f368cf4ec15 (patch)
treea89afe9780f1e2986989b150f1653df188631f03
parentab338eadfacb7651540ef5f1babbc8d18f4ab451 (diff)
parent02357e459be7fb2014f57f1a86b38897c2c0816b (diff)
downloadrust-f70f6ec56751e5095830fd93d0607f368cf4ec15.tar.gz
rust-f70f6ec56751e5095830fd93d0607f368cf4ec15.zip
Rollup merge of #54603 - davidtwco:issue-54559, r=nikomatsakis
Add `crate::` to trait suggestions in Rust 2018.

Fixes #54559.

In the 2018 edition, when suggesting traits to import that implement a
given method that is being invoked, suggestions will now include the
`crate::` prefix if the suggested trait is local to the current crate.

r? @nikomatsakis
-rw-r--r--src/librustc/session/mod.rs13
-rw-r--r--src/librustc/ty/item_path.rs147
-rw-r--r--src/librustc_codegen_utils/symbol_names.rs3
-rw-r--r--src/librustc_typeck/check/method/suggest.rs25
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/test/ui/rust-2018/auxiliary/trait-import-suggestions.rs15
-rw-r--r--src/test/ui/rust-2018/trait-import-suggestions.rs41
-rw-r--r--src/test/ui/rust-2018/trait-import-suggestions.stderr43
8 files changed, 241 insertions, 49 deletions
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 79d06cd7f12..3c209a43246 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -28,17 +28,16 @@ use util::common::ProfileQueriesMsg;
 use rustc_data_structures::base_n;
 use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, RwLock};
 
-use syntax::ast::NodeId;
 use errors::{self, DiagnosticBuilder, DiagnosticId, Applicability};
 use errors::emitter::{Emitter, EmitterWriter};
+use syntax::ast::{self, NodeId};
 use syntax::edition::Edition;
+use syntax::feature_gate::{self, AttributeType};
 use syntax::json::JsonEmitter;
-use syntax::feature_gate;
-use syntax::parse;
-use syntax::parse::ParseSess;
-use syntax::{ast, source_map};
-use syntax::feature_gate::AttributeType;
-use syntax_pos::{MultiSpan, Span, symbol::Symbol};
+use syntax::source_map;
+use syntax::symbol::Symbol;
+use syntax::parse::{self, ParseSess};
+use syntax_pos::{MultiSpan, Span};
 use util::profiling::SelfProfiler;
 
 use rustc_target::spec::PanicStrategy;
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index 1b4ff18f6b8..c8d104e6c32 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -13,14 +13,16 @@ use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use ty::{self, Ty, TyCtxt};
 use middle::cstore::{ExternCrate, ExternCrateSource};
 use syntax::ast;
-use syntax::symbol::Symbol;
-use syntax::symbol::LocalInternedString;
+use syntax::symbol::{keywords, LocalInternedString, Symbol};
+use syntax_pos::edition::Edition;
 
 use std::cell::Cell;
+use std::fmt::Debug;
 
 thread_local! {
     static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
     static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
+    static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
 }
 
 /// Enforces that item_path_str always returns an absolute path and
@@ -51,6 +53,17 @@ pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
     })
 }
 
+/// Add the `crate::` prefix to paths where appropriate.
+pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
+    SHOULD_PREFIX_WITH_CRATE.with(|flag| {
+        let old = flag.get();
+        flag.set(true);
+        let result = f();
+        flag.set(old);
+        result
+    })
+}
+
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Returns a string identifying this def-id. This string is
     /// suitable for user output. It is relative to the current crate
@@ -64,7 +77,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             }
         });
         let mut buffer = LocalPathBuffer::new(mode);
-        self.push_item_path(&mut buffer, def_id);
+        debug!("item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
+        self.push_item_path(&mut buffer, def_id, false);
         buffer.into_string()
     }
 
@@ -77,16 +91,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// suitable for user output. It always begins with a crate identifier.
     pub fn absolute_item_path_str(self, def_id: DefId) -> String {
         let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
-        self.push_item_path(&mut buffer, def_id);
+        debug!("absolute_item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
+        self.push_item_path(&mut buffer, def_id, false);
         buffer.into_string()
     }
 
     /// Returns the "path" to a particular crate. This can proceed in
     /// various ways, depending on the `root_mode` of the `buffer`.
     /// (See `RootMode` enum for more details.)
-    pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum)
-        where T: ItemPathBuffer
+    ///
+    /// `pushed_prelude_crate` argument should be `true` when the buffer
+    /// has had a prelude crate pushed to it. If this is the case, then
+    /// we do not want to prepend `crate::` (as that would not be a valid
+    /// path).
+    pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum, pushed_prelude_crate: bool)
+        where T: ItemPathBuffer + Debug
     {
+        debug!(
+            "push_krate_path: buffer={:?} cnum={:?} LOCAL_CRATE={:?}",
+            buffer, cnum, LOCAL_CRATE
+        );
         match *buffer.root_mode() {
             RootMode::Local => {
                 // In local mode, when we encounter a crate other than
@@ -109,16 +133,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                         ..
                     }) = *opt_extern_crate
                     {
-                        self.push_item_path(buffer, def_id);
+                        debug!("push_krate_path: def_id={:?}", def_id);
+                        self.push_item_path(buffer, def_id, pushed_prelude_crate);
                     } else {
-                        buffer.push(&self.crate_name(cnum).as_str());
+                        let name = self.crate_name(cnum).as_str();
+                        debug!("push_krate_path: name={:?}", name);
+                        buffer.push(&name);
                     }
+                } else if self.sess.edition() == Edition::Edition2018 && !pushed_prelude_crate {
+                    SHOULD_PREFIX_WITH_CRATE.with(|flag| {
+                        // We only add the `crate::` keyword where appropriate. In particular,
+                        // when we've not previously pushed a prelude crate to this path.
+                        if flag.get() {
+                            buffer.push(&keywords::Crate.name().as_str())
+                        }
+                    })
                 }
             }
             RootMode::Absolute => {
                 // In absolute mode, just write the crate name
                 // unconditionally.
-                buffer.push(&self.original_crate_name(cnum).as_str());
+                let name = self.original_crate_name(cnum).as_str();
+                debug!("push_krate_path: original_name={:?}", name);
+                buffer.push(&name);
             }
         }
     }
@@ -126,13 +163,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// If possible, this pushes a global path resolving to `external_def_id` that is visible
     /// from at least one local module and returns true. If the crate defining `external_def_id` is
     /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
-    pub fn try_push_visible_item_path<T>(self, buffer: &mut T, external_def_id: DefId) -> bool
-        where T: ItemPathBuffer
+    pub fn try_push_visible_item_path<T>(
+        self,
+        buffer: &mut T,
+        external_def_id: DefId,
+        pushed_prelude_crate: bool,
+    ) -> bool
+        where T: ItemPathBuffer + Debug
     {
+        debug!(
+            "try_push_visible_item_path: buffer={:?} external_def_id={:?}",
+            buffer, external_def_id
+        );
         let visible_parent_map = self.visible_parent_map(LOCAL_CRATE);
 
         let (mut cur_def, mut cur_path) = (external_def_id, Vec::<LocalInternedString>::new());
         loop {
+            debug!(
+                "try_push_visible_item_path: cur_def={:?} cur_path={:?} CRATE_DEF_INDEX={:?}",
+                cur_def, cur_path, CRATE_DEF_INDEX,
+            );
             // If `cur_def` is a direct or injected extern crate, push the path to the crate
             // followed by the path to the item within the crate and return.
             if cur_def.index == CRATE_DEF_INDEX {
@@ -142,7 +192,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                         direct: true,
                         ..
                     }) => {
-                        self.push_item_path(buffer, def_id);
+                        debug!("try_push_visible_item_path: def_id={:?}", def_id);
+                        self.push_item_path(buffer, def_id, pushed_prelude_crate);
                         cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
                         return true;
                     }
@@ -156,6 +207,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             }
 
             let mut cur_def_key = self.def_key(cur_def);
+            debug!("try_push_visible_item_path: cur_def_key={:?}", cur_def_key);
 
             // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
             if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
@@ -175,6 +227,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     Symbol::intern("<unnamed>").as_str()
                 }
             });
+            debug!("try_push_visible_item_path: symbol={:?}", symbol);
             cur_path.push(symbol);
 
             match visible_parent_map.get(&cur_def) {
@@ -184,24 +237,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId)
-        where T: ItemPathBuffer
+    pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId, pushed_prelude_crate: bool)
+        where T: ItemPathBuffer + Debug
     {
+        debug!(
+            "push_item_path: buffer={:?} def_id={:?} pushed_prelude_crate={:?}",
+            buffer, def_id, pushed_prelude_crate
+        );
         match *buffer.root_mode() {
             RootMode::Local if !def_id.is_local() =>
-                if self.try_push_visible_item_path(buffer, def_id) { return },
+                if self.try_push_visible_item_path(buffer, def_id, pushed_prelude_crate) { return },
             _ => {}
         }
 
         let key = self.def_key(def_id);
+        debug!("push_item_path: key={:?}", key);
         match key.disambiguated_data.data {
             DefPathData::CrateRoot => {
                 assert!(key.parent.is_none());
-                self.push_krate_path(buffer, def_id.krate);
+                self.push_krate_path(buffer, def_id.krate, pushed_prelude_crate);
             }
 
             DefPathData::Impl => {
-                self.push_impl_path(buffer, def_id);
+                self.push_impl_path(buffer, def_id, pushed_prelude_crate);
             }
 
             // Unclear if there is any value in distinguishing these.
@@ -224,22 +282,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             data @ DefPathData::ClosureExpr |
             data @ DefPathData::ImplTrait |
             data @ DefPathData::GlobalMetaData(..) => {
-                let parent_def_id = self.parent_def_id(def_id).unwrap();
-                self.push_item_path(buffer, parent_def_id);
+                let parent_did = self.parent_def_id(def_id).unwrap();
+
+                // Keep track of whether we are one recursion away from the `CrateRoot` and
+                // pushing the name of a prelude crate. If we are, we'll want to know this when
+                // printing the `CrateRoot` so we don't prepend a `crate::` to paths.
+                let mut is_prelude_crate = false;
+                if let DefPathData::CrateRoot = self.def_key(parent_did).disambiguated_data.data {
+                    if self.sess.extern_prelude.contains(&data.as_interned_str().as_symbol()) {
+                        is_prelude_crate = true;
+                    }
+                }
+
+                self.push_item_path(
+                    buffer, parent_did, pushed_prelude_crate || is_prelude_crate
+                );
                 buffer.push(&data.as_interned_str().as_symbol().as_str());
-            }
+            },
+
             DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
                 let parent_def_id = self.parent_def_id(def_id).unwrap();
-                self.push_item_path(buffer, parent_def_id);
+                self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
             }
         }
     }
 
-    fn push_impl_path<T>(self,
-                         buffer: &mut T,
-                         impl_def_id: DefId)
-        where T: ItemPathBuffer
+    fn push_impl_path<T>(
+        self,
+         buffer: &mut T,
+         impl_def_id: DefId,
+         pushed_prelude_crate: bool,
+    )
+        where T: ItemPathBuffer + Debug
     {
+        debug!("push_impl_path: buffer={:?} impl_def_id={:?}", buffer, impl_def_id);
         let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
 
         // Always use types for non-local impls, where types are always
@@ -251,7 +327,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         };
 
         if !use_types {
-            return self.push_impl_path_fallback(buffer, impl_def_id);
+            return self.push_impl_path_fallback(buffer, impl_def_id, pushed_prelude_crate);
         }
 
         // Decide whether to print the parent path for the impl.
@@ -275,7 +351,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             // If the impl is not co-located with either self-type or
             // trait-type, then fallback to a format that identifies
             // the module more clearly.
-            self.push_item_path(buffer, parent_def_id);
+            self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
             if let Some(trait_ref) = impl_trait_ref {
                 buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
             } else {
@@ -301,13 +377,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         match self_ty.sty {
             ty::Adt(adt_def, substs) => {
                 if substs.types().next().is_none() { // ignore regions
-                    self.push_item_path(buffer, adt_def.did);
+                    self.push_item_path(buffer, adt_def.did, pushed_prelude_crate);
                 } else {
                     buffer.push(&format!("<{}>", self_ty));
                 }
             }
 
-            ty::Foreign(did) => self.push_item_path(buffer, did),
+            ty::Foreign(did) => self.push_item_path(buffer, did, pushed_prelude_crate),
 
             ty::Bool |
             ty::Char |
@@ -324,16 +400,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn push_impl_path_fallback<T>(self,
-                                  buffer: &mut T,
-                                  impl_def_id: DefId)
-        where T: ItemPathBuffer
+    fn push_impl_path_fallback<T>(
+        self,
+        buffer: &mut T,
+        impl_def_id: DefId,
+        pushed_prelude_crate: bool,
+    )
+        where T: ItemPathBuffer + Debug
     {
         // If no type info is available, fall back to
         // pretty printing some span information. This should
         // only occur very early in the compiler pipeline.
         let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
-        self.push_item_path(buffer, parent_def_id);
+        self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
         let node_id = self.hir.as_local_node_id(impl_def_id).unwrap();
         let item = self.hir.expect_item(node_id);
         let span_str = self.sess.source_map().span_to_string(item.span);
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index 39b88b225ed..c1e80234a77 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -228,7 +228,7 @@ fn get_symbol_hash<'a, 'tcx>(
 fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::SymbolName {
     let mut buffer = SymbolPathBuffer::new();
     item_path::with_forced_absolute_paths(|| {
-        tcx.push_item_path(&mut buffer, def_id);
+        tcx.push_item_path(&mut buffer, def_id, false);
     });
     buffer.into_interned()
 }
@@ -338,6 +338,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
 //
 // To be able to work on all platforms and get *some* reasonable output, we
 // use C++ name-mangling.
+#[derive(Debug)]
 struct SymbolPathBuffer {
     result: String,
     temp_buf: String,
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index f5d332521ff..28b9dcb9bfd 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -16,6 +16,7 @@ use rustc::hir::map as hir_map;
 use hir::Node;
 use rustc_data_structures::sync::Lrc;
 use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
+use rustc::ty::item_path::with_crate_prefix;
 use hir::def::Def;
 use hir::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::lang_items::FnOnceTraitLangItem;
@@ -515,7 +516,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 } else {
                     "\n"
                 };
-                format!("use {};\n{}", self.tcx.item_path_str(*did), additional_newline)
+                format!(
+                    "use {};\n{}",
+                    with_crate_prefix(|| self.tcx.item_path_str(*did)),
+                    additional_newline
+                )
             }).collect();
 
             err.span_suggestions_with_applicability(
@@ -528,12 +533,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let limit = if candidates.len() == 5 { 5 } else { 4 };
             for (i, trait_did) in candidates.iter().take(limit).enumerate() {
                 if candidates.len() > 1 {
-                    msg.push_str(&format!("\ncandidate #{}: `use {};`",
-                                            i + 1,
-                                            self.tcx.item_path_str(*trait_did)));
+                    msg.push_str(
+                        &format!(
+                            "\ncandidate #{}: `use {};`",
+                            i + 1,
+                            with_crate_prefix(|| self.tcx.item_path_str(*trait_did))
+                        )
+                    );
                 } else {
-                    msg.push_str(&format!("\n`use {};`",
-                                            self.tcx.item_path_str(*trait_did)));
+                    msg.push_str(
+                        &format!(
+                            "\n`use {};`",
+                            with_crate_prefix(|| self.tcx.item_path_str(*trait_did))
+                        )
+                    );
                 }
             }
             if candidates.len() > limit {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a91f2fd7474..371b631723a 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -3990,6 +3990,7 @@ pub fn path_to_def(tcx: &TyCtxt, path: &[&str]) -> Option<DefId> {
 
 pub fn get_path_for_type<F>(tcx: TyCtxt, def_id: DefId, def_ctor: F) -> hir::Path
 where F: Fn(DefId) -> Def {
+    #[derive(Debug)]
     struct AbsolutePathBuffer {
         names: Vec<String>,
     }
@@ -4007,7 +4008,7 @@ where F: Fn(DefId) -> Def {
 
     let mut apb = AbsolutePathBuffer { names: vec![] };
 
-    tcx.push_item_path(&mut apb, def_id);
+    tcx.push_item_path(&mut apb, def_id, false);
 
     hir::Path {
         span: DUMMY_SP,
diff --git a/src/test/ui/rust-2018/auxiliary/trait-import-suggestions.rs b/src/test/ui/rust-2018/auxiliary/trait-import-suggestions.rs
new file mode 100644
index 00000000000..611fa83854b
--- /dev/null
+++ b/src/test/ui/rust-2018/auxiliary/trait-import-suggestions.rs
@@ -0,0 +1,15 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Baz {
+    fn baz(&self) { }
+}
+
+impl Baz for u32 { }
diff --git a/src/test/ui/rust-2018/trait-import-suggestions.rs b/src/test/ui/rust-2018/trait-import-suggestions.rs
new file mode 100644
index 00000000000..d603d8212ed
--- /dev/null
+++ b/src/test/ui/rust-2018/trait-import-suggestions.rs
@@ -0,0 +1,41 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+// aux-build:trait-import-suggestions.rs
+// compile-flags:--extern trait-import-suggestions
+
+mod foo {
+    mod foobar {
+        pub(crate) trait Foobar {
+            fn foobar(&self) { }
+        }
+
+        impl Foobar for u32 { }
+    }
+
+    pub(crate) trait Bar {
+        fn bar(&self) { }
+    }
+
+    impl Bar for u32 { }
+
+    fn in_foo() {
+        let x: u32 = 22;
+        x.foobar();
+    }
+}
+
+fn main() {
+    let x: u32 = 22;
+    x.bar();
+    x.baz();
+    let y = u32::from_str("33");
+}
diff --git a/src/test/ui/rust-2018/trait-import-suggestions.stderr b/src/test/ui/rust-2018/trait-import-suggestions.stderr
new file mode 100644
index 00000000000..59fe7b958e3
--- /dev/null
+++ b/src/test/ui/rust-2018/trait-import-suggestions.stderr
@@ -0,0 +1,43 @@
+error[E0599]: no method named `foobar` found for type `u32` in the current scope
+  --> $DIR/trait-import-suggestions.rs:32:11
+   |
+LL |         x.foobar();
+   |           ^^^^^^
+   |
+   = help: items from traits can only be used if the trait is in scope
+   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+           `use crate::foo::foobar::Foobar;`
+
+error[E0599]: no method named `bar` found for type `u32` in the current scope
+  --> $DIR/trait-import-suggestions.rs:38:7
+   |
+LL |     x.bar();
+   |       ^^^
+   |
+   = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   |
+LL | use crate::foo::Bar;
+   |
+
+error[E0599]: no method named `baz` found for type `u32` in the current scope
+  --> $DIR/trait-import-suggestions.rs:39:7
+   |
+LL |     x.baz();
+   |       ^^^
+
+error[E0599]: no function or associated item named `from_str` found for type `u32` in the current scope
+  --> $DIR/trait-import-suggestions.rs:40:13
+   |
+LL |     let y = u32::from_str("33");
+   |             ^^^^^^^^^^^^^ function or associated item not found in `u32`
+   |
+   = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   |
+LL | use std::str::FromStr;
+   |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0599`.