1
Fork 0

Attempt to resolve linking issues.

This commit takes a different approach to add the `crate::` prefix to
item paths than previous commits. Previously, recursion was stopped
after a prelude crate name was pushed to the path. It is theorized that
this was the cause of the linking issues since the same path logic is
used for symbol names and that not recursing meant that details were
being missed that affect symbol names. As of this commit, instead of
ceasing recursion, a flag is passed through to any subsequent recursive
calls so that the same effect can be achieved by checking that flag.
This commit is contained in:
David Wood 2018-09-28 00:56:41 +02:00
parent 4cbd397ce8
commit 02357e459b
No known key found for this signature in database
GPG key ID: 01760B4F9F53F154
3 changed files with 59 additions and 43 deletions

View file

@ -78,7 +78,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
});
let mut buffer = LocalPathBuffer::new(mode);
debug!("item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
self.push_item_path(&mut buffer, def_id);
self.push_item_path(&mut buffer, def_id, false);
buffer.into_string()
}
@ -92,14 +92,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn absolute_item_path_str(self, def_id: DefId) -> String {
let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
debug!("absolute_item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
self.push_item_path(&mut 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)
///
/// `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!(
@ -129,19 +134,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}) = *opt_extern_crate
{
debug!("push_krate_path: def_id={:?}", def_id);
self.push_item_path(buffer, def_id);
self.push_item_path(buffer, def_id, pushed_prelude_crate);
} else {
let name = self.crate_name(cnum).as_str();
debug!("push_krate_path: name={:?}", name);
buffer.push(&name);
}
} else if self.sess.edition() == Edition::Edition2018 {
} else if self.sess.edition() == Edition::Edition2018 && !pushed_prelude_crate {
SHOULD_PREFIX_WITH_CRATE.with(|flag| {
// We only add the `crate::` keyword where appropriate. This
// is only possible because of the invariant in `push_item_path`
// that this function will not be called after printing the path
// to an item in the standard library. Without this invariant,
// we would print `crate::std::..` here.
// 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())
}
@ -161,7 +163,12 @@ 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
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!(
@ -186,7 +193,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
..
}) => {
debug!("try_push_visible_item_path: def_id={:?}", def_id);
self.push_item_path(buffer, def_id);
self.push_item_path(buffer, def_id, pushed_prelude_crate);
cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
return true;
}
@ -230,13 +237,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
}
pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId)
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={:?}", buffer, def_id);
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 },
_ => {}
}
@ -245,11 +255,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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.
@ -272,34 +282,37 @@ 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();
let parent_did = self.parent_def_id(def_id).unwrap();
match self.def_key(parent_def_id).disambiguated_data.data {
// Skip recursing to print the crate root depending on the
// current name.
//
// In particular, don't recurse to print the crate root if we
// just printed `std`. In doing this, we are able to add
// `crate::` to trait import suggestions.
DefPathData::CrateRoot if self.sess.extern_prelude.contains(
&data.as_interned_str().as_symbol()
) => {},
_ => self.push_item_path(buffer, parent_def_id),
// 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)
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);
@ -314,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.
@ -338,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 {
@ -364,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 |
@ -387,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)
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);

View file

@ -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()
}

View file

@ -4008,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,