mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 17:53:56 +00:00
Prefer stable paths over unstable ones in import path calculation
This commit is contained in:
parent
712e67cf11
commit
e63e323823
@ -37,6 +37,20 @@ pub fn find_path_prefixed(
|
|||||||
find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std)
|
find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
enum Stability {
|
||||||
|
Unstable,
|
||||||
|
Stable,
|
||||||
|
}
|
||||||
|
use Stability::*;
|
||||||
|
|
||||||
|
fn zip_stability(a: Stability, b: Stability) -> Stability {
|
||||||
|
match (a, b) {
|
||||||
|
(Stable, Stable) => Stable,
|
||||||
|
_ => Unstable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const MAX_PATH_LEN: usize = 15;
|
const MAX_PATH_LEN: usize = 15;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
@ -95,7 +109,8 @@ fn find_path_inner(
|
|||||||
MAX_PATH_LEN,
|
MAX_PATH_LEN,
|
||||||
prefixed,
|
prefixed,
|
||||||
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
|
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
|
||||||
);
|
)
|
||||||
|
.map(|(item, _)| item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - if the item is already in scope, return the name under which it is
|
// - if the item is already in scope, return the name under which it is
|
||||||
@ -143,6 +158,7 @@ fn find_path_inner(
|
|||||||
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
|
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
|
||||||
scope_name,
|
scope_name,
|
||||||
)
|
)
|
||||||
|
.map(|(item, _)| item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_path_for_module(
|
fn find_path_for_module(
|
||||||
@ -155,7 +171,7 @@ fn find_path_for_module(
|
|||||||
max_len: usize,
|
max_len: usize,
|
||||||
prefixed: Option<PrefixKind>,
|
prefixed: Option<PrefixKind>,
|
||||||
prefer_no_std: bool,
|
prefer_no_std: bool,
|
||||||
) -> Option<ModPath> {
|
) -> Option<(ModPath, Stability)> {
|
||||||
if max_len == 0 {
|
if max_len == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -165,19 +181,19 @@ fn find_path_for_module(
|
|||||||
let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into()));
|
let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into()));
|
||||||
if prefixed.is_none() {
|
if prefixed.is_none() {
|
||||||
if let Some(scope_name) = scope_name {
|
if let Some(scope_name) = scope_name {
|
||||||
return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
|
return Some((ModPath::from_segments(PathKind::Plain, Some(scope_name)), Stable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - if the item is the crate root, return `crate`
|
// - if the item is the crate root, return `crate`
|
||||||
if module_id == crate_root {
|
if module_id == crate_root {
|
||||||
return Some(ModPath::from_segments(PathKind::Crate, None));
|
return Some((ModPath::from_segments(PathKind::Crate, None), Stable));
|
||||||
}
|
}
|
||||||
|
|
||||||
// - if relative paths are fine, check if we are searching for a parent
|
// - if relative paths are fine, check if we are searching for a parent
|
||||||
if prefixed.filter(PrefixKind::is_absolute).is_none() {
|
if prefixed.filter(PrefixKind::is_absolute).is_none() {
|
||||||
if let modpath @ Some(_) = find_self_super(def_map, module_id, from) {
|
if let modpath @ Some(_) = find_self_super(def_map, module_id, from) {
|
||||||
return modpath;
|
return modpath.zip(Some(Stable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,14 +217,14 @@ fn find_path_for_module(
|
|||||||
} else {
|
} else {
|
||||||
PathKind::Plain
|
PathKind::Plain
|
||||||
};
|
};
|
||||||
return Some(ModPath::from_segments(kind, Some(name)));
|
return Some((ModPath::from_segments(kind, Some(name)), Stable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let value @ Some(_) =
|
if let value @ Some(_) =
|
||||||
find_in_prelude(db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
|
find_in_prelude(db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
|
||||||
{
|
{
|
||||||
return value;
|
return value.zip(Some(Stable));
|
||||||
}
|
}
|
||||||
calculate_best_path(
|
calculate_best_path(
|
||||||
db,
|
db,
|
||||||
@ -301,11 +317,19 @@ fn calculate_best_path(
|
|||||||
mut prefixed: Option<PrefixKind>,
|
mut prefixed: Option<PrefixKind>,
|
||||||
prefer_no_std: bool,
|
prefer_no_std: bool,
|
||||||
scope_name: Option<Name>,
|
scope_name: Option<Name>,
|
||||||
) -> Option<ModPath> {
|
) -> Option<(ModPath, Stability)> {
|
||||||
if max_len <= 1 {
|
if max_len <= 1 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let mut best_path = None;
|
let mut best_path = None;
|
||||||
|
let update_best_path =
|
||||||
|
|best_path: &mut Option<_>, new_path: (ModPath, Stability)| match best_path {
|
||||||
|
Some((old_path, old_stability)) => {
|
||||||
|
*old_path = new_path.0;
|
||||||
|
*old_stability = zip_stability(*old_stability, new_path.1);
|
||||||
|
}
|
||||||
|
None => *best_path = Some(new_path),
|
||||||
|
};
|
||||||
// Recursive case:
|
// Recursive case:
|
||||||
// - otherwise, look for modules containing (reexporting) it and import it from one of those
|
// - otherwise, look for modules containing (reexporting) it and import it from one of those
|
||||||
if item.krate(db) == Some(from.krate) {
|
if item.krate(db) == Some(from.krate) {
|
||||||
@ -328,14 +352,14 @@ fn calculate_best_path(
|
|||||||
prefixed,
|
prefixed,
|
||||||
prefer_no_std,
|
prefer_no_std,
|
||||||
) {
|
) {
|
||||||
path.push_segment(name);
|
path.0.push_segment(name);
|
||||||
|
|
||||||
let new_path = match best_path {
|
let new_path = match best_path.take() {
|
||||||
Some(best_path) => select_best_path(best_path, path, prefer_no_std),
|
Some(best_path) => select_best_path(best_path, path, prefer_no_std),
|
||||||
None => path,
|
None => path,
|
||||||
};
|
};
|
||||||
best_path_len = new_path.len();
|
best_path_len = new_path.0.len();
|
||||||
best_path = Some(new_path);
|
update_best_path(&mut best_path, new_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -354,7 +378,7 @@ fn calculate_best_path(
|
|||||||
|
|
||||||
// Determine best path for containing module and append last segment from `info`.
|
// Determine best path for containing module and append last segment from `info`.
|
||||||
// FIXME: we should guide this to look up the path locally, or from the same crate again?
|
// FIXME: we should guide this to look up the path locally, or from the same crate again?
|
||||||
let mut path = find_path_for_module(
|
let (mut path, path_stability) = find_path_for_module(
|
||||||
db,
|
db,
|
||||||
def_map,
|
def_map,
|
||||||
visited_modules,
|
visited_modules,
|
||||||
@ -367,16 +391,19 @@ fn calculate_best_path(
|
|||||||
)?;
|
)?;
|
||||||
cov_mark::hit!(partially_imported);
|
cov_mark::hit!(partially_imported);
|
||||||
path.push_segment(info.name.clone());
|
path.push_segment(info.name.clone());
|
||||||
Some(path)
|
Some((
|
||||||
|
path,
|
||||||
|
zip_stability(path_stability, if info.is_unstable { Unstable } else { Stable }),
|
||||||
|
))
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
for path in extern_paths {
|
for path in extern_paths {
|
||||||
let new_path = match best_path {
|
let new_path = match best_path.take() {
|
||||||
Some(best_path) => select_best_path(best_path, path, prefer_no_std),
|
Some(best_path) => select_best_path(best_path, path, prefer_no_std),
|
||||||
None => path,
|
None => path,
|
||||||
};
|
};
|
||||||
best_path = Some(new_path);
|
update_best_path(&mut best_path, new_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(module) = item.module(db) {
|
if let Some(module) = item.module(db) {
|
||||||
@ -387,15 +414,24 @@ fn calculate_best_path(
|
|||||||
}
|
}
|
||||||
match prefixed.map(PrefixKind::prefix) {
|
match prefixed.map(PrefixKind::prefix) {
|
||||||
Some(prefix) => best_path.or_else(|| {
|
Some(prefix) => best_path.or_else(|| {
|
||||||
scope_name.map(|scope_name| ModPath::from_segments(prefix, Some(scope_name)))
|
scope_name.map(|scope_name| (ModPath::from_segments(prefix, Some(scope_name)), Stable))
|
||||||
}),
|
}),
|
||||||
None => best_path,
|
None => best_path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath {
|
fn select_best_path(
|
||||||
|
old_path: (ModPath, Stability),
|
||||||
|
new_path: (ModPath, Stability),
|
||||||
|
prefer_no_std: bool,
|
||||||
|
) -> (ModPath, Stability) {
|
||||||
|
match (old_path.1, new_path.1) {
|
||||||
|
(Stable, Unstable) => return old_path,
|
||||||
|
(Unstable, Stable) => return new_path,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
|
const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
|
||||||
match (old_path.segments().first(), new_path.segments().first()) {
|
match (old_path.0.segments().first(), new_path.0.segments().first()) {
|
||||||
(Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => {
|
(Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => {
|
||||||
let rank = match prefer_no_std {
|
let rank = match prefer_no_std {
|
||||||
false => |name: &Name| match name {
|
false => |name: &Name| match name {
|
||||||
@ -416,7 +452,7 @@ fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -
|
|||||||
match nrank.cmp(&orank) {
|
match nrank.cmp(&orank) {
|
||||||
Ordering::Less => old_path,
|
Ordering::Less => old_path,
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
if new_path.len() < old_path.len() {
|
if new_path.0.len() < old_path.0.len() {
|
||||||
new_path
|
new_path
|
||||||
} else {
|
} else {
|
||||||
old_path
|
old_path
|
||||||
@ -426,7 +462,7 @@ fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if new_path.len() < old_path.len() {
|
if new_path.0.len() < old_path.0.len() {
|
||||||
new_path
|
new_path
|
||||||
} else {
|
} else {
|
||||||
old_path
|
old_path
|
||||||
@ -1360,4 +1396,29 @@ pub mod ops {
|
|||||||
"std::ops::Deref",
|
"std::ops::Deref",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn respect_unstable_modules() {
|
||||||
|
check_found_path(
|
||||||
|
r#"
|
||||||
|
//- /main.rs crate:main deps:std,core
|
||||||
|
#![no_std]
|
||||||
|
extern crate std;
|
||||||
|
$0
|
||||||
|
//- /longer.rs crate:std deps:core
|
||||||
|
pub mod error {
|
||||||
|
pub use core::error::Error;
|
||||||
|
}
|
||||||
|
//- /core.rs crate:core
|
||||||
|
pub mod error {
|
||||||
|
#![unstable(feature = "error_in_core", issue = "103765")]
|
||||||
|
pub trait Error {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"std::error::Error",
|
||||||
|
"std::error::Error",
|
||||||
|
"std::error::Error",
|
||||||
|
"std::error::Error",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,8 @@ pub struct ImportInfo {
|
|||||||
pub is_trait_assoc_item: bool,
|
pub is_trait_assoc_item: bool,
|
||||||
/// Whether this item is annotated with `#[doc(hidden)]`.
|
/// Whether this item is annotated with `#[doc(hidden)]`.
|
||||||
pub is_doc_hidden: bool,
|
pub is_doc_hidden: bool,
|
||||||
|
/// Whether this item is annotated with `#[unstable(..)]`.
|
||||||
|
pub is_unstable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A map from publicly exported items to its name.
|
/// A map from publicly exported items to its name.
|
||||||
@ -117,7 +119,6 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap<ItemIn
|
|||||||
|
|
||||||
for (name, per_ns) in visible_items {
|
for (name, per_ns) in visible_items {
|
||||||
for (item, import) in per_ns.iter_items() {
|
for (item, import) in per_ns.iter_items() {
|
||||||
// FIXME: Not yet used, but will be once we handle doc(hidden) import sources
|
|
||||||
let attr_id = if let Some(import) = import {
|
let attr_id = if let Some(import) = import {
|
||||||
match import {
|
match import {
|
||||||
ImportOrExternCrate::ExternCrate(id) => Some(id.into()),
|
ImportOrExternCrate::ExternCrate(id) => Some(id.into()),
|
||||||
@ -129,28 +130,59 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap<ItemIn
|
|||||||
ItemInNs::Macros(id) => Some(id.into()),
|
ItemInNs::Macros(id) => Some(id.into()),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let is_doc_hidden =
|
let status @ (is_doc_hidden, is_unstable) =
|
||||||
attr_id.map_or(false, |attr_id| db.attrs(attr_id).has_doc_hidden());
|
attr_id.map_or((false, false), |attr_id| {
|
||||||
|
let attrs = db.attrs(attr_id);
|
||||||
|
(attrs.has_doc_hidden(), attrs.is_unstable())
|
||||||
|
});
|
||||||
|
|
||||||
let import_info = ImportInfo {
|
let import_info = ImportInfo {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
container: module,
|
container: module,
|
||||||
is_trait_assoc_item: false,
|
is_trait_assoc_item: false,
|
||||||
is_doc_hidden,
|
is_doc_hidden,
|
||||||
|
is_unstable,
|
||||||
};
|
};
|
||||||
|
|
||||||
match depth_map.entry(item) {
|
match depth_map.entry(item) {
|
||||||
Entry::Vacant(entry) => _ = entry.insert((depth, is_doc_hidden)),
|
Entry::Vacant(entry) => _ = entry.insert((depth, status)),
|
||||||
Entry::Occupied(mut entry) => {
|
Entry::Occupied(mut entry) => {
|
||||||
let &(occ_depth, occ_is_doc_hidden) = entry.get();
|
let &(occ_depth, (occ_is_doc_hidden, occ_is_unstable)) = entry.get();
|
||||||
// Prefer the one that is not doc(hidden),
|
(depth, occ_depth);
|
||||||
// Otherwise, if both have the same doc(hidden)-ness and the new path is shorter, prefer that one.
|
let overwrite = match (
|
||||||
let overwrite_entry = occ_is_doc_hidden && !is_doc_hidden
|
is_doc_hidden,
|
||||||
|| occ_is_doc_hidden == is_doc_hidden && depth < occ_depth;
|
occ_is_doc_hidden,
|
||||||
if !overwrite_entry {
|
is_unstable,
|
||||||
|
occ_is_unstable,
|
||||||
|
) {
|
||||||
|
// no change of hiddeness or unstableness
|
||||||
|
(true, true, true, true)
|
||||||
|
| (true, true, false, false)
|
||||||
|
| (false, false, true, true)
|
||||||
|
| (false, false, false, false) => depth < occ_depth,
|
||||||
|
|
||||||
|
// either less hidden or less unstable, accept
|
||||||
|
(true, true, false, true)
|
||||||
|
| (false, true, true, true)
|
||||||
|
| (false, true, false, true)
|
||||||
|
| (false, true, false, false)
|
||||||
|
| (false, false, false, true) => true,
|
||||||
|
// more hidden or unstable, discard
|
||||||
|
(true, true, true, false)
|
||||||
|
| (true, false, true, true)
|
||||||
|
| (true, false, true, false)
|
||||||
|
| (true, false, false, false)
|
||||||
|
| (false, false, true, false) => false,
|
||||||
|
|
||||||
|
// exchanges doc(hidden) for unstable (and vice-versa),
|
||||||
|
(true, false, false, true) | (false, true, true, false) => {
|
||||||
|
depth < occ_depth
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !overwrite {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
entry.insert((depth, is_doc_hidden));
|
entry.insert((depth, status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,11 +236,13 @@ fn collect_trait_assoc_items(
|
|||||||
ItemInNs::Values(module_def_id)
|
ItemInNs::Values(module_def_id)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let attrs = &db.attrs(item.into());
|
||||||
let assoc_item_info = ImportInfo {
|
let assoc_item_info = ImportInfo {
|
||||||
container: trait_import_info.container,
|
container: trait_import_info.container,
|
||||||
name: assoc_item_name.clone(),
|
name: assoc_item_name.clone(),
|
||||||
is_trait_assoc_item: true,
|
is_trait_assoc_item: true,
|
||||||
is_doc_hidden: db.attrs(item.into()).has_doc_hidden(),
|
is_doc_hidden: attrs.has_doc_hidden(),
|
||||||
|
is_unstable: attrs.is_unstable(),
|
||||||
};
|
};
|
||||||
map.insert(assoc_item, assoc_item_info);
|
map.insert(assoc_item, assoc_item_info);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user