Skip to content

Commit f70f6ec

Browse files
authored
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
2 parents ab338ea + 02357e4 commit f70f6ec

File tree

8 files changed

+241
-49
lines changed

8 files changed

+241
-49
lines changed

src/librustc/session/mod.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,16 @@ use util::common::ProfileQueriesMsg;
2828
use rustc_data_structures::base_n;
2929
use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, RwLock};
3030

31-
use syntax::ast::NodeId;
3231
use errors::{self, DiagnosticBuilder, DiagnosticId, Applicability};
3332
use errors::emitter::{Emitter, EmitterWriter};
33+
use syntax::ast::{self, NodeId};
3434
use syntax::edition::Edition;
35+
use syntax::feature_gate::{self, AttributeType};
3536
use syntax::json::JsonEmitter;
36-
use syntax::feature_gate;
37-
use syntax::parse;
38-
use syntax::parse::ParseSess;
39-
use syntax::{ast, source_map};
40-
use syntax::feature_gate::AttributeType;
41-
use syntax_pos::{MultiSpan, Span, symbol::Symbol};
37+
use syntax::source_map;
38+
use syntax::symbol::Symbol;
39+
use syntax::parse::{self, ParseSess};
40+
use syntax_pos::{MultiSpan, Span};
4241
use util::profiling::SelfProfiler;
4342

4443
use rustc_target::spec::PanicStrategy;

src/librustc/ty/item_path.rs

Lines changed: 113 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@ use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
1313
use ty::{self, Ty, TyCtxt};
1414
use middle::cstore::{ExternCrate, ExternCrateSource};
1515
use syntax::ast;
16-
use syntax::symbol::Symbol;
17-
use syntax::symbol::LocalInternedString;
16+
use syntax::symbol::{keywords, LocalInternedString, Symbol};
17+
use syntax_pos::edition::Edition;
1818

1919
use std::cell::Cell;
20+
use std::fmt::Debug;
2021

2122
thread_local! {
2223
static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
2324
static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
25+
static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
2426
}
2527

2628
/// 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 {
5153
})
5254
}
5355

56+
/// Add the `crate::` prefix to paths where appropriate.
57+
pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
58+
SHOULD_PREFIX_WITH_CRATE.with(|flag| {
59+
let old = flag.get();
60+
flag.set(true);
61+
let result = f();
62+
flag.set(old);
63+
result
64+
})
65+
}
66+
5467
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
5568
/// Returns a string identifying this def-id. This string is
5669
/// suitable for user output. It is relative to the current crate
@@ -64,7 +77,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
6477
}
6578
});
6679
let mut buffer = LocalPathBuffer::new(mode);
67-
self.push_item_path(&mut buffer, def_id);
80+
debug!("item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
81+
self.push_item_path(&mut buffer, def_id, false);
6882
buffer.into_string()
6983
}
7084

@@ -77,16 +91,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
7791
/// suitable for user output. It always begins with a crate identifier.
7892
pub fn absolute_item_path_str(self, def_id: DefId) -> String {
7993
let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
80-
self.push_item_path(&mut buffer, def_id);
94+
debug!("absolute_item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
95+
self.push_item_path(&mut buffer, def_id, false);
8196
buffer.into_string()
8297
}
8398

8499
/// Returns the "path" to a particular crate. This can proceed in
85100
/// various ways, depending on the `root_mode` of the `buffer`.
86101
/// (See `RootMode` enum for more details.)
87-
pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum)
88-
where T: ItemPathBuffer
102+
///
103+
/// `pushed_prelude_crate` argument should be `true` when the buffer
104+
/// has had a prelude crate pushed to it. If this is the case, then
105+
/// we do not want to prepend `crate::` (as that would not be a valid
106+
/// path).
107+
pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum, pushed_prelude_crate: bool)
108+
where T: ItemPathBuffer + Debug
89109
{
110+
debug!(
111+
"push_krate_path: buffer={:?} cnum={:?} LOCAL_CRATE={:?}",
112+
buffer, cnum, LOCAL_CRATE
113+
);
90114
match *buffer.root_mode() {
91115
RootMode::Local => {
92116
// In local mode, when we encounter a crate other than
@@ -109,30 +133,56 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
109133
..
110134
}) = *opt_extern_crate
111135
{
112-
self.push_item_path(buffer, def_id);
136+
debug!("push_krate_path: def_id={:?}", def_id);
137+
self.push_item_path(buffer, def_id, pushed_prelude_crate);
113138
} else {
114-
buffer.push(&self.crate_name(cnum).as_str());
139+
let name = self.crate_name(cnum).as_str();
140+
debug!("push_krate_path: name={:?}", name);
141+
buffer.push(&name);
115142
}
143+
} else if self.sess.edition() == Edition::Edition2018 && !pushed_prelude_crate {
144+
SHOULD_PREFIX_WITH_CRATE.with(|flag| {
145+
// We only add the `crate::` keyword where appropriate. In particular,
146+
// when we've not previously pushed a prelude crate to this path.
147+
if flag.get() {
148+
buffer.push(&keywords::Crate.name().as_str())
149+
}
150+
})
116151
}
117152
}
118153
RootMode::Absolute => {
119154
// In absolute mode, just write the crate name
120155
// unconditionally.
121-
buffer.push(&self.original_crate_name(cnum).as_str());
156+
let name = self.original_crate_name(cnum).as_str();
157+
debug!("push_krate_path: original_name={:?}", name);
158+
buffer.push(&name);
122159
}
123160
}
124161
}
125162

126163
/// If possible, this pushes a global path resolving to `external_def_id` that is visible
127164
/// from at least one local module and returns true. If the crate defining `external_def_id` is
128165
/// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
129-
pub fn try_push_visible_item_path<T>(self, buffer: &mut T, external_def_id: DefId) -> bool
130-
where T: ItemPathBuffer
166+
pub fn try_push_visible_item_path<T>(
167+
self,
168+
buffer: &mut T,
169+
external_def_id: DefId,
170+
pushed_prelude_crate: bool,
171+
) -> bool
172+
where T: ItemPathBuffer + Debug
131173
{
174+
debug!(
175+
"try_push_visible_item_path: buffer={:?} external_def_id={:?}",
176+
buffer, external_def_id
177+
);
132178
let visible_parent_map = self.visible_parent_map(LOCAL_CRATE);
133179

134180
let (mut cur_def, mut cur_path) = (external_def_id, Vec::<LocalInternedString>::new());
135181
loop {
182+
debug!(
183+
"try_push_visible_item_path: cur_def={:?} cur_path={:?} CRATE_DEF_INDEX={:?}",
184+
cur_def, cur_path, CRATE_DEF_INDEX,
185+
);
136186
// If `cur_def` is a direct or injected extern crate, push the path to the crate
137187
// followed by the path to the item within the crate and return.
138188
if cur_def.index == CRATE_DEF_INDEX {
@@ -142,7 +192,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
142192
direct: true,
143193
..
144194
}) => {
145-
self.push_item_path(buffer, def_id);
195+
debug!("try_push_visible_item_path: def_id={:?}", def_id);
196+
self.push_item_path(buffer, def_id, pushed_prelude_crate);
146197
cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
147198
return true;
148199
}
@@ -156,6 +207,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
156207
}
157208

158209
let mut cur_def_key = self.def_key(cur_def);
210+
debug!("try_push_visible_item_path: cur_def_key={:?}", cur_def_key);
159211

160212
// For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
161213
if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
@@ -175,6 +227,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
175227
Symbol::intern("<unnamed>").as_str()
176228
}
177229
});
230+
debug!("try_push_visible_item_path: symbol={:?}", symbol);
178231
cur_path.push(symbol);
179232

180233
match visible_parent_map.get(&cur_def) {
@@ -184,24 +237,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
184237
}
185238
}
186239

187-
pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId)
188-
where T: ItemPathBuffer
240+
pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId, pushed_prelude_crate: bool)
241+
where T: ItemPathBuffer + Debug
189242
{
243+
debug!(
244+
"push_item_path: buffer={:?} def_id={:?} pushed_prelude_crate={:?}",
245+
buffer, def_id, pushed_prelude_crate
246+
);
190247
match *buffer.root_mode() {
191248
RootMode::Local if !def_id.is_local() =>
192-
if self.try_push_visible_item_path(buffer, def_id) { return },
249+
if self.try_push_visible_item_path(buffer, def_id, pushed_prelude_crate) { return },
193250
_ => {}
194251
}
195252

196253
let key = self.def_key(def_id);
254+
debug!("push_item_path: key={:?}", key);
197255
match key.disambiguated_data.data {
198256
DefPathData::CrateRoot => {
199257
assert!(key.parent.is_none());
200-
self.push_krate_path(buffer, def_id.krate);
258+
self.push_krate_path(buffer, def_id.krate, pushed_prelude_crate);
201259
}
202260

203261
DefPathData::Impl => {
204-
self.push_impl_path(buffer, def_id);
262+
self.push_impl_path(buffer, def_id, pushed_prelude_crate);
205263
}
206264

207265
// Unclear if there is any value in distinguishing these.
@@ -224,22 +282,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
224282
data @ DefPathData::ClosureExpr |
225283
data @ DefPathData::ImplTrait |
226284
data @ DefPathData::GlobalMetaData(..) => {
227-
let parent_def_id = self.parent_def_id(def_id).unwrap();
228-
self.push_item_path(buffer, parent_def_id);
285+
let parent_did = self.parent_def_id(def_id).unwrap();
286+
287+
// Keep track of whether we are one recursion away from the `CrateRoot` and
288+
// pushing the name of a prelude crate. If we are, we'll want to know this when
289+
// printing the `CrateRoot` so we don't prepend a `crate::` to paths.
290+
let mut is_prelude_crate = false;
291+
if let DefPathData::CrateRoot = self.def_key(parent_did).disambiguated_data.data {
292+
if self.sess.extern_prelude.contains(&data.as_interned_str().as_symbol()) {
293+
is_prelude_crate = true;
294+
}
295+
}
296+
297+
self.push_item_path(
298+
buffer, parent_did, pushed_prelude_crate || is_prelude_crate
299+
);
229300
buffer.push(&data.as_interned_str().as_symbol().as_str());
230-
}
301+
},
302+
231303
DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
232304
let parent_def_id = self.parent_def_id(def_id).unwrap();
233-
self.push_item_path(buffer, parent_def_id);
305+
self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
234306
}
235307
}
236308
}
237309

238-
fn push_impl_path<T>(self,
239-
buffer: &mut T,
240-
impl_def_id: DefId)
241-
where T: ItemPathBuffer
310+
fn push_impl_path<T>(
311+
self,
312+
buffer: &mut T,
313+
impl_def_id: DefId,
314+
pushed_prelude_crate: bool,
315+
)
316+
where T: ItemPathBuffer + Debug
242317
{
318+
debug!("push_impl_path: buffer={:?} impl_def_id={:?}", buffer, impl_def_id);
243319
let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
244320

245321
// Always use types for non-local impls, where types are always
@@ -251,7 +327,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
251327
};
252328

253329
if !use_types {
254-
return self.push_impl_path_fallback(buffer, impl_def_id);
330+
return self.push_impl_path_fallback(buffer, impl_def_id, pushed_prelude_crate);
255331
}
256332

257333
// Decide whether to print the parent path for the impl.
@@ -275,7 +351,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
275351
// If the impl is not co-located with either self-type or
276352
// trait-type, then fallback to a format that identifies
277353
// the module more clearly.
278-
self.push_item_path(buffer, parent_def_id);
354+
self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
279355
if let Some(trait_ref) = impl_trait_ref {
280356
buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
281357
} else {
@@ -301,13 +377,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
301377
match self_ty.sty {
302378
ty::Adt(adt_def, substs) => {
303379
if substs.types().next().is_none() { // ignore regions
304-
self.push_item_path(buffer, adt_def.did);
380+
self.push_item_path(buffer, adt_def.did, pushed_prelude_crate);
305381
} else {
306382
buffer.push(&format!("<{}>", self_ty));
307383
}
308384
}
309385

310-
ty::Foreign(did) => self.push_item_path(buffer, did),
386+
ty::Foreign(did) => self.push_item_path(buffer, did, pushed_prelude_crate),
311387

312388
ty::Bool |
313389
ty::Char |
@@ -324,16 +400,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
324400
}
325401
}
326402

327-
fn push_impl_path_fallback<T>(self,
328-
buffer: &mut T,
329-
impl_def_id: DefId)
330-
where T: ItemPathBuffer
403+
fn push_impl_path_fallback<T>(
404+
self,
405+
buffer: &mut T,
406+
impl_def_id: DefId,
407+
pushed_prelude_crate: bool,
408+
)
409+
where T: ItemPathBuffer + Debug
331410
{
332411
// If no type info is available, fall back to
333412
// pretty printing some span information. This should
334413
// only occur very early in the compiler pipeline.
335414
let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
336-
self.push_item_path(buffer, parent_def_id);
415+
self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
337416
let node_id = self.hir.as_local_node_id(impl_def_id).unwrap();
338417
let item = self.hir.expect_item(node_id);
339418
let span_str = self.sess.source_map().span_to_string(item.span);

src/librustc_codegen_utils/symbol_names.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ fn get_symbol_hash<'a, 'tcx>(
228228
fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::SymbolName {
229229
let mut buffer = SymbolPathBuffer::new();
230230
item_path::with_forced_absolute_paths(|| {
231-
tcx.push_item_path(&mut buffer, def_id);
231+
tcx.push_item_path(&mut buffer, def_id, false);
232232
});
233233
buffer.into_interned()
234234
}
@@ -338,6 +338,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
338338
//
339339
// To be able to work on all platforms and get *some* reasonable output, we
340340
// use C++ name-mangling.
341+
#[derive(Debug)]
341342
struct SymbolPathBuffer {
342343
result: String,
343344
temp_buf: String,

src/librustc_typeck/check/method/suggest.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc::hir::map as hir_map;
1616
use hir::Node;
1717
use rustc_data_structures::sync::Lrc;
1818
use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
19+
use rustc::ty::item_path::with_crate_prefix;
1920
use hir::def::Def;
2021
use hir::def_id::{CRATE_DEF_INDEX, DefId};
2122
use middle::lang_items::FnOnceTraitLangItem;
@@ -515,7 +516,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
515516
} else {
516517
"\n"
517518
};
518-
format!("use {};\n{}", self.tcx.item_path_str(*did), additional_newline)
519+
format!(
520+
"use {};\n{}",
521+
with_crate_prefix(|| self.tcx.item_path_str(*did)),
522+
additional_newline
523+
)
519524
}).collect();
520525

521526
err.span_suggestions_with_applicability(
@@ -528,12 +533,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
528533
let limit = if candidates.len() == 5 { 5 } else { 4 };
529534
for (i, trait_did) in candidates.iter().take(limit).enumerate() {
530535
if candidates.len() > 1 {
531-
msg.push_str(&format!("\ncandidate #{}: `use {};`",
532-
i + 1,
533-
self.tcx.item_path_str(*trait_did)));
536+
msg.push_str(
537+
&format!(
538+
"\ncandidate #{}: `use {};`",
539+
i + 1,
540+
with_crate_prefix(|| self.tcx.item_path_str(*trait_did))
541+
)
542+
);
534543
} else {
535-
msg.push_str(&format!("\n`use {};`",
536-
self.tcx.item_path_str(*trait_did)));
544+
msg.push_str(
545+
&format!(
546+
"\n`use {};`",
547+
with_crate_prefix(|| self.tcx.item_path_str(*trait_did))
548+
)
549+
);
537550
}
538551
}
539552
if candidates.len() > limit {

0 commit comments

Comments
 (0)