Skip to content
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

Prefer suggestion paths which are not doc-hidden #87349

Closed
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
9 changes: 9 additions & 0 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,3 +580,12 @@ impl NestedMetaItem {
MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
}
}

/// Return true if the attributes contain `#[doc(hidden)]`
pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
attrs
.iter()
.filter(|attr| attr.has_name(sym::doc))
.filter_map(ast::Attribute::meta_item_list)
.any(|l| list_contains_name(&l, sym::hidden))
}
6 changes: 4 additions & 2 deletions compiler/rustc_data_structures/src/stable_hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,11 @@ where
}
}

impl<A, CTX> HashStable<CTX> for SmallVec<[A; 1]>
impl<T, CTX, const N: usize> HashStable<CTX> for SmallVec<[T; N]>
where
A: HashStable<CTX>,
T: HashStable<CTX>,
[T; N]: smallvec::Array,
<[T; N] as smallvec::Array>::Item: HashStable<CTX>,
{
#[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
Expand Down
122 changes: 70 additions & 52 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ provide! { <'tcx> tcx, def_id, other, cdata,
generator_kind => { cdata.generator_kind(def_id.index) }
opt_def_kind => { Some(cdata.def_kind(def_id.index)) }
def_span => { cdata.get_span(def_id.index, &tcx.sess) }
def_ident_span => {
cdata.try_item_ident(def_id.index, &tcx.sess).ok().map(|ident| ident.span)
def_ident => {
cdata.try_item_ident(def_id.index, &tcx.sess).ok()
}
lookup_stability => {
cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s))
Expand Down Expand Up @@ -290,15 +290,11 @@ pub fn provide(providers: &mut Providers) {
// external item that is visible from at least one local module) to a
// sufficiently visible parent (considering modules that re-export the
// external item to be parents).
visible_parent_map: |tcx, ()| {
use std::collections::hash_map::Entry;
use std::collections::vec_deque::VecDeque;
visible_parents_map: |tcx, ()| {
use rustc_data_structures::fx::FxHashSet;
use std::collections::VecDeque;

let mut visible_parent_map: DefIdMap<DefId> = Default::default();
// This is a secondary visible_parent_map, storing the DefId of parents that re-export
// the child as `_`. Since we prefer parents that don't do this, merge this map at the
// end, only if we're missing any keys from the former.
let mut fallback_map: DefIdMap<DefId> = Default::default();
let mut visible_parents_map: DefIdMap<SmallVec<[DefId; 4]>> = DefIdMap::default();

// Issue 46112: We want the map to prefer the shortest
// paths when reporting the path to an item. Therefore we
Expand All @@ -310,59 +306,81 @@ pub fn provide(providers: &mut Providers) {
// only get paths that are locally minimal with respect to
// whatever crate we happened to encounter first in this
// traversal, but not globally minimal across all crates.
let bfs_queue = &mut VecDeque::new();

for &cnum in tcx.crates(()) {
// Ignore crates without a corresponding local `extern crate` item.
if tcx.missing_extern_crate_item(cnum) {
continue;
let mut bfs_queue = VecDeque::default();

bfs_queue.extend(
tcx.crates(())
.into_iter()
// Ignore crates without a corresponding local `extern crate` item.
.filter(|cnum| !tcx.missing_extern_crate_item(**cnum))
.map(|cnum| DefId { krate: *cnum, index: CRATE_DEF_INDEX }),
);

// Iterate over graph using BFS.
// Filter out any non-public items.
while let Some(parent) = bfs_queue.pop_front() {
for child in tcx
.item_children(parent)
.iter()
.filter(|child| child.vis.is_public())
.filter_map(|child| child.res.opt_def_id())
{
visible_parents_map
.entry(child)
.or_insert_with(|| {
// If we encounter node the first time
// add it to queue for next iterations
bfs_queue.push_back(child);
Default::default()
})
.push(parent);
}
}

bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
// Iterate over parents vector to remove duplicate elements
// while preserving order
let mut dedup_set = FxHashSet::default();
for (_, parents) in &mut visible_parents_map {
parents.retain(|parent| dedup_set.insert(*parent));

// Reuse hashset allocation.
dedup_set.clear();
}

let mut add_child = |bfs_queue: &mut VecDeque<_>, export: &Export, parent: DefId| {
if !export.vis.is_public() {
return;
}
visible_parents_map
},
best_visible_parent: |tcx, child| {
// Use `min_by_key` because it returns
// first match in case keys are equal
tcx.visible_parents_map(())
.get(&child)?
.into_iter()
.min_by_key(|parent| {
// If this is just regular export in another module, assign it a neutral score.
let mut score = 0;

// If child and parent are local, we prefer them
if child.is_local() && parent.is_local() {
score += 1;
}

if let Some(child) = export.res.opt_def_id() {
if export.ident.name == kw::Underscore {
fallback_map.insert(child, parent);
return;
// Even if child and parent are local, if parent is `#[doc(hidden)]`
// We reduce their score to avoid showing items not popping in documentation.
if ast::attr::is_doc_hidden(tcx.item_attrs(**parent)) {
score -= 2;
}

match visible_parent_map.entry(child) {
Entry::Occupied(mut entry) => {
// If `child` is defined in crate `cnum`, ensure
// that it is mapped to a parent in `cnum`.
if child.is_local() && entry.get().is_local() {
entry.insert(parent);
}
}
Entry::Vacant(entry) => {
entry.insert(parent);
bfs_queue.push_back(child);
// If parent identifier is _ we prefer it only as last resort if other items are not available
if let Some(ident) = tcx.def_ident(**parent) {
if ident.name == kw::Underscore {
score -= 3;
}
}
}
};

while let Some(def) = bfs_queue.pop_front() {
for child in tcx.item_children(def).iter() {
add_child(bfs_queue, child, def);
}
}

// Fill in any missing entries with the (less preferable) path ending in `::_`.
// We still use this path in a diagnostic that suggests importing `::*`.
for (child, parent) in fallback_map {
visible_parent_map.entry(child).or_insert(parent);
}

visible_parent_map
-score
})
.map(ToOwned::to_owned)
},

dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)),
has_global_allocator: |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -977,8 +977,8 @@ rustc_queries! {
}

/// Gets the span for the identifier of the definition.
query def_ident_span(def_id: DefId) -> Option<Span> {
desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) }
query def_ident(def_id: DefId) -> Option<Ident> {
desc { |tcx| "looking up ident for `{}`'s identifier", tcx.def_path_str(def_id) }
separate_provide_extern
}

Expand Down Expand Up @@ -1552,10 +1552,14 @@ rustc_queries! {
desc { "calculating the missing lang items in a crate" }
separate_provide_extern
}
query visible_parent_map(_: ()) -> DefIdMap<DefId> {

query visible_parents_map(_: ()) -> DefIdMap<smallvec::SmallVec<[DefId; 4]>> {
storage(ArenaCacheSelector<'tcx>)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what ArenaCacheSelector does here, should I use it instead of Lrc<_>?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#70674

It seems it's a mem optimization, but if we don't see any regression here, then it likely doesn't matter?

The code looks r=me, although I'm not 100% sure about the arena cache change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we changing it in this PR? Was there a performance hit or some other error that motivated the change from arena cache to Lrc?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a performance hit before #89395 and #89120 were merged. The arena change may no longer be necessary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless we have reason to believe we should change this, I don't think we should change it. That reason should probably look something like "we have a perf run that shows an improvement when dropping it", or at the very least a neutral perf run with just that change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should still be done in a separate PR, so we can independently evaluate its effects.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Mark-Simulacrum So, is this discussion resolved then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I'd expect that separate PR to likely get filed before this merges (in order to attempt to prevent the regression here).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Mark-Simulacrum I opened #92169 #92168 for that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and #92170

desc { "calculating the visible parent map" }
}
query best_visible_parent(child: DefId) -> Option<DefId> {
desc { "calculating best visible parent" }
}
query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> {
storage(ArenaCacheSelector<'tcx>)
desc { "calculating trimmed def paths" }
Expand Down
8 changes: 3 additions & 5 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,6 @@ pub trait PrettyPrinter<'tcx>:
return Ok((self, false));
}

let visible_parent_map = self.tcx().visible_parent_map(());

let mut cur_def_key = self.tcx().def_key(def_id);
debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);

Expand All @@ -404,7 +402,7 @@ pub trait PrettyPrinter<'tcx>:
cur_def_key = self.tcx().def_key(parent);
}

let visible_parent = match visible_parent_map.get(&def_id).cloned() {
let visible_parent = match self.tcx().best_visible_parent(def_id) {
Some(parent) => parent,
None => return Ok((self, false)),
};
Expand All @@ -431,7 +429,7 @@ pub trait PrettyPrinter<'tcx>:
// `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
// private so the "true" path to `CommandExt` isn't accessible.
//
// In this case, the `visible_parent_map` will look something like this:
// In this case, the `visible_parents_map` will look something like this:
//
// (child) -> (parent)
// `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
Expand All @@ -451,7 +449,7 @@ pub trait PrettyPrinter<'tcx>:
// do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
// the visible parent (`std::os`). If these do not match, then we iterate over
// the children of the visible parent (as was done when computing
// `visible_parent_map`), looking for the specific child we currently have and then
// `visible_parents_map`), looking for the specific child we currently have and then
// have access to the re-exported name.
DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => {
// Item might be re-exported several times, but filter for the one
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::traits::specialization_graph;
use crate::traits::{self, ImplSource};
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, Ident, ParamEnvAnd, Ty, TyCtxt};
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::steal::Steal;
Expand Down
27 changes: 12 additions & 15 deletions compiler/rustc_ty_utils/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
use rustc_span::{sym, Span};
use rustc_span::{sym, symbol::Ident};
use rustc_trait_selection::traits;

fn sized_constraint_for_ty<'tcx>(
Expand Down Expand Up @@ -216,19 +216,16 @@ fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
ty::AssocItems::new(items)
}

fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
tcx.hir()
.get_if_local(def_id)
.and_then(|node| match node {
// A `Ctor` doesn't have an identifier itself, but its parent
// struct/variant does. Compare with `hir::Map::opt_span`.
hir::Node::Ctor(ctor) => ctor
.ctor_hir_id()
.and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
.and_then(|parent| parent.ident()),
_ => node.ident(),
})
.map(|ident| ident.span)
fn def_ident(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ident> {
tcx.hir().get_if_local(def_id).and_then(|node| match node {
// A `Ctor` doesn't have an identifier itself, but its parent
// struct/variant does. Compare with `hir::Map::opt_span`.
hir::Node::Ctor(ctor) => ctor
.ctor_hir_id()
.and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
.and_then(|parent| parent.ident()),
_ => node.ident(),
})
}

/// If the given `DefId` describes an item belonging to a trait,
Expand Down Expand Up @@ -624,7 +621,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
associated_item_def_ids,
associated_items,
adt_sized_constraint,
def_ident_span,
def_ident,
param_env,
param_env_reveal_all_normalized,
trait_of_item,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

if let Some(def_id) = def_id {
if let Some(def_span) = tcx.def_ident_span(def_id) {
let mut spans: MultiSpan = def_span.into();
if let Some(def_ident) = tcx.def_ident(def_id) {
let mut spans: MultiSpan = def_ident.span.into();

let params = tcx
.hir()
Expand Down
22 changes: 10 additions & 12 deletions compiler/rustc_typeck/src/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc_hir::{ExprKind, Node, QPath};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams, StripReferences};
use rustc_middle::ty::print::with_crate_prefix;
use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
Expand Down Expand Up @@ -1310,17 +1310,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mut msg: String,
candidates: Vec<DefId>,
) {
let parent_map = self.tcx.visible_parent_map(());

// Separate out candidates that must be imported with a glob, because they are named `_`
// and cannot be referred with their identifier.
let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| {
if let Some(parent_did) = parent_map.get(trait_did) {
if let Some(parent_did) = self.tcx.best_visible_parent(*trait_did) {
// If the item is re-exported as `_`, we should suggest a glob-import instead.
if Some(*parent_did) != self.tcx.parent(*trait_did)
if Some(parent_did) != self.tcx.best_visible_parent(*trait_did)
&& self
.tcx
.item_children(*parent_did)
.item_children(parent_did)
.iter()
.filter(|child| child.res.opt_def_id() == Some(*trait_did))
.all(|child| child.ident.name == kw::Underscore)
Expand All @@ -1347,14 +1345,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});

let glob_path_strings = globs.iter().map(|trait_did| {
let parent_did = parent_map.get(trait_did).unwrap();

// Produce an additional newline to separate the new use statement
// from the directly following item.
let additional_newline = if found_use { "" } else { "\n" };
format!(
"use {}::*; // trait {}\n{}",
with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
with_crate_prefix(|| self
.tcx
.def_path_str(self.tcx.best_visible_parent(*trait_did).unwrap())),
self.tcx.item_name(*trait_did),
additional_newline
)
Expand Down Expand Up @@ -1385,19 +1383,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (i, trait_did) in
globs.iter().take(limit.saturating_sub(candidates.len())).enumerate()
{
let parent_did = parent_map.get(trait_did).unwrap();
let parent_did = self.tcx.best_visible_parent(*trait_did).unwrap();

if candidates.len() + globs.len() > 1 {
msg.push_str(&format!(
"\ncandidate #{}: `use {}::*; // trait {}`",
candidates.len() + i + 1,
with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
with_crate_prefix(|| self.tcx.def_path_str(parent_did)),
self.tcx.item_name(*trait_did),
));
} else {
msg.push_str(&format!(
"\n`use {}::*; // trait {}`",
with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
with_crate_prefix(|| self.tcx.def_path_str(parent_did)),
self.tcx.item_name(*trait_did),
));
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_typeck/src/check/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let last_subpat_span = *subpat_spans.last().unwrap();
let res_span = self.tcx.def_span(res.def_id());
let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
let def_ident_span =
self.tcx.def_ident(res.def_id()).map(|ident| ident.span).unwrap_or(res_span);
let field_def_spans = if fields.is_empty() {
vec![res_span]
} else {
Expand Down
Loading