From dadce2521e332a6d8f8704ce440637b8a4df7c66 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 18:38:54 -0400 Subject: [PATCH] always print def-path in Debug impl for DefId I also added an `opt_def_path` so that we can deal with DefIds that are missing a `DefPath` entry. --- src/librustc/hir/def_id.rs | 19 ++++++---------- src/librustc/middle/cstore.rs | 4 ++-- src/librustc/ty/mod.rs | 37 ++++++++++++++++++++++++++++---- src/librustc_metadata/csearch.rs | 2 +- src/librustc_metadata/decoder.rs | 13 ++++++++--- 5 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index a3b83ec5be4b..16afa705e391 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -58,19 +58,14 @@ impl fmt::Debug for DefId { write!(f, "DefId {{ krate: {:?}, node: {:?}", self.krate, self.index)?; - // Unfortunately, there seems to be no way to attempt to print - // a path for a def-id, so I'll just make a best effort for now - // and otherwise fallback to just printing the crate/node pair - if self.is_local() { // (1) - // (1) side-step fact that not all external things have paths at - // the moment, such as type parameters - ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - write!(f, " => {}", tcx.item_path_str(*self))?; + ty::tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_path) = tcx.opt_def_path(*self) { + write!(f, " => {}", def_path.to_string(tcx))?; } - Ok(()) - })?; - } + } + Ok(()) + })?; write!(f, " }}") } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index b33bc520fe21..52645883a8be 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -233,7 +233,7 @@ pub trait CrateStore<'tcx> { def: DefKey) -> Option; fn def_key(&self, def: DefId) -> hir_map::DefKey; - fn relative_def_path(&self, def: DefId) -> hir_map::DefPath; + fn relative_def_path(&self, def: DefId) -> Option; fn variant_kind(&self, def_id: DefId) -> Option; fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; @@ -430,7 +430,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // resolve fn def_key(&self, def: DefId) -> hir_map::DefKey { bug!("def_key") } - fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { bug!("relative_def_path") } + fn relative_def_path(&self, def: DefId) -> Option { bug!("relative_def_path") } fn variant_kind(&self, def_id: DefId) -> Option { bug!("variant_kind") } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { bug!("struct_ctor_def_id") } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 78358ce534d9..53838b0760a7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2437,12 +2437,41 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Returns the `DefPath` of an item. Note that if `id` is not - /// local to this crate -- or is inlined into this crate -- the - /// result will be a non-local `DefPath`. + /// Convert a `DefId` into its fully expanded `DefPath` (every + /// `DefId` is really just an interned def-path). + /// + /// Note that if `id` is not local to this crate -- or is + /// inlined into this crate -- the result will be a non-local + /// `DefPath`. + /// + /// This function is only safe to use when you are sure that the + /// full def-path is accessible. Examples that are known to be + /// safe are local def-ids or items; see `opt_def_path` for more + /// details. pub fn def_path(self, id: DefId) -> ast_map::DefPath { + self.opt_def_path(id).unwrap_or_else(|| { + bug!("could not load def-path for {:?}", id) + }) + } + + /// Convert a `DefId` into its fully expanded `DefPath` (every + /// `DefId` is really just an interned def-path). + /// + /// When going across crates, we do not save the full info for + /// every cross-crate def-id, and hence we may not always be able + /// to create a def-path. Therefore, this returns + /// `Option` to cover that possibility. It will always + /// return `Some` for local def-ids, however, as well as for + /// items. The problems arise with "minor" def-ids like those + /// associated with a pattern, `impl Trait`, or other internal + /// detail to a fn. + /// + /// Note that if `id` is not local to this crate -- or is + /// inlined into this crate -- the result will be a non-local + /// `DefPath`. + pub fn opt_def_path(self, id: DefId) -> Option { if id.is_local() { - self.map.def_path(id) + Some(self.map.def_path(id)) } else { self.sess.cstore.relative_def_path(id) } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 5e5cc7e1e610..d7ca93235fdd 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -435,7 +435,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::def_key(&cdata, def.index) } - fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { + fn relative_def_path(&self, def: DefId) -> Option { // See `Note` above in `def_key()` for why this read is // commented out: // diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d75d5a3b3544..5bad89f1a593 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -759,7 +759,7 @@ pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: krate: cdata.cnum, index: def_key(cdata, id).parent.unwrap() }; - let mut parent_def_path = def_path(cdata, id); + let mut parent_def_path = def_path(cdata, id).unwrap(); parent_def_path.data.pop(); if let Some(ast_doc) = reader::maybe_get_doc(item_doc, tag_ast as usize) { let ii = decode_inlined_item(cdata, @@ -1626,9 +1626,16 @@ fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { } } -pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath { +// Returns the path leading to the thing with this `id`. Note that +// some def-ids don't wind up in the metadata, so `def_path` sometimes +// returns `None` +pub fn def_path(cdata: Cmd, id: DefIndex) -> Option { debug!("def_path(id={:?})", id); - hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent)) + if cdata.get_item(id).is_some() { + Some(hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent))) + } else { + None + } } pub fn get_panic_strategy(data: &[u8]) -> PanicStrategy {