Skip to content

Add crate:: to trait suggestions in Rust 2018. #54603

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
147 changes: 113 additions & 34 deletions src/librustc/ty/item_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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()
}

Expand All @@ -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
Expand All @@ -109,30 +133,56 @@ 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);
}
}
}

/// 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 {
Expand All @@ -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;
}
Expand All @@ -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 {
Expand All @@ -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) {
Expand All @@ -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.
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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 {
Expand All @@ -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 |
Expand All @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_codegen_utils/symbol_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down Expand Up @@ -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,
Expand Down
25 changes: 19 additions & 6 deletions src/librustc_typeck/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand All @@ -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 {
Expand Down
Loading