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
This commit is contained in:
commit
f70f6ec567
8 changed files with 241 additions and 49 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
15
src/test/ui/rust-2018/auxiliary/trait-import-suggestions.rs
Normal file
15
src/test/ui/rust-2018/auxiliary/trait-import-suggestions.rs
Normal file
|
|
@ -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 { }
|
||||
41
src/test/ui/rust-2018/trait-import-suggestions.rs
Normal file
41
src/test/ui/rust-2018/trait-import-suggestions.rs
Normal file
|
|
@ -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");
|
||||
}
|
||||
43
src/test/ui/rust-2018/trait-import-suggestions.stderr
Normal file
43
src/test/ui/rust-2018/trait-import-suggestions.stderr
Normal file
|
|
@ -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`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue