Auto merge of #119988 - lnicola:sync-from-ra, r=lnicola

Subtree update of `rust-analyzer`

r? ghost
This commit is contained in:
bors 2024-01-15 18:43:19 +00:00
commit bfcc027a75
104 changed files with 1652 additions and 1026 deletions

View File

@ -513,7 +513,8 @@ dependencies = [
"mbe",
"once_cell",
"profile",
"rustc-dependencies",
"ra-ap-rustc_abi",
"ra-ap-rustc_parse_format",
"rustc-hash",
"smallvec",
"span",
@ -579,7 +580,8 @@ dependencies = [
"oorandom",
"profile",
"project-model",
"rustc-dependencies",
"ra-ap-rustc_abi",
"ra-ap-rustc_index",
"rustc-hash",
"scoped-tls",
"smallvec",
@ -1196,7 +1198,7 @@ dependencies = [
"drop_bomb",
"expect-test",
"limit",
"rustc-dependencies",
"ra-ap-rustc_lexer",
"sourcegen",
"stdx",
]
@ -1540,7 +1542,6 @@ dependencies = [
"profile",
"project-model",
"rayon",
"rustc-dependencies",
"rustc-hash",
"scip",
"serde",
@ -1567,9 +1568,9 @@ dependencies = [
[[package]]
name = "rust-analyzer-salsa"
version = "0.17.0-pre.4"
version = "0.17.0-pre.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16c42b8737c320578b441a82daf7cdf8d897468de64e8a774fa54b53a50b6cc0"
checksum = "ca9d387a9801f4fb9b366789ad1bfc08448cafc49cf148d907cfcd88ab665d7f"
dependencies = [
"indexmap",
"lock_api",
@ -1579,13 +1580,14 @@ dependencies = [
"rust-analyzer-salsa-macros",
"rustc-hash",
"smallvec",
"triomphe",
]
[[package]]
name = "rust-analyzer-salsa-macros"
version = "0.17.0-pre.4"
version = "0.17.0-pre.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db72b0883f3592ade2be15a10583c75e0b269ec26e1190800fda2e2ce5ae6634"
checksum = "a2035f385d7fae31e9b086f40b272ee1d79c484472f31c9a10348a406e841eaf"
dependencies = [
"heck",
"proc-macro2",
@ -1599,16 +1601,6 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-dependencies"
version = "0.0.0"
dependencies = [
"ra-ap-rustc_abi",
"ra-ap-rustc_index",
"ra-ap-rustc_lexer",
"ra-ap-rustc_parse_format",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
@ -1751,6 +1743,12 @@ dependencies = [
"vfs",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "static_assertions"
version = "1.1.0"
@ -1808,9 +1806,9 @@ dependencies = [
"proc-macro2",
"profile",
"quote",
"ra-ap-rustc_lexer",
"rayon",
"rowan",
"rustc-dependencies",
"rustc-hash",
"smol_str",
"sourcegen",
@ -2028,9 +2026,13 @@ dependencies = [
[[package]]
name = "triomphe"
version = "0.1.10"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0c5a71827ac326072b6405552093e2ad2accd25a32fd78d4edc82d98c7f2409"
checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3"
dependencies = [
"serde",
"stable_deref_trait",
]
[[package]]
name = "tt"

View File

@ -78,7 +78,11 @@ toolchain = { path = "./crates/toolchain", version = "0.0.0" }
tt = { path = "./crates/tt", version = "0.0.0" }
vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
vfs = { path = "./crates/vfs", version = "0.0.0" }
rustc-dependencies = { path = "./crates/rustc-dependencies", version = "0.0.0" }
ra-ap-rustc_lexer = { version = "0.21.0", default-features = false }
ra-ap-rustc_parse_format = { version = "0.21.0", default-features = false }
ra-ap-rustc_index = { version = "0.21.0", default-features = false }
ra-ap-rustc_abi = { version = "0.21.0", default-features = false }
# local crates that aren't published to crates.io. These should not have versions.
sourcegen = { path = "./crates/sourcegen" }
@ -108,7 +112,7 @@ itertools = "0.12.0"
libc = "0.2.150"
nohash-hasher = "0.2.0"
rayon = "1.8.0"
rust-analyzer-salsa = "0.17.0-pre.4"
rust-analyzer-salsa = "0.17.0-pre.5"
rustc-hash = "1.1.0"
semver = "1.0.14"
serde = { version = "1.0.192", features = ["derive"] }

View File

@ -7,7 +7,6 @@ mod change;
use std::panic;
use rustc_hash::FxHashSet;
use syntax::{ast, Parse, SourceFile};
use triomphe::Arc;
@ -44,12 +43,13 @@ pub trait Upcast<T: ?Sized> {
}
pub const DEFAULT_PARSE_LRU_CAP: usize = 128;
pub const DEFAULT_BORROWCK_LRU_CAP: usize = 256;
pub trait FileLoader {
/// Text of the file.
fn file_text(&self, file_id: FileId) -> Arc<str>;
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId>;
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>;
}
/// Database which stores all significant input facts: source code and project
@ -84,19 +84,21 @@ pub trait SourceDatabaseExt: SourceDatabase {
#[salsa::input]
fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>;
}
fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<FxHashSet<CrateId>> {
fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<[CrateId]> {
let graph = db.crate_graph();
let res = graph
let mut crates = graph
.iter()
.filter(|&krate| {
let root_file = graph[krate].root_file_id;
db.file_source_root(root_file) == id
})
.collect();
Arc::new(res)
.collect::<Vec<_>>();
crates.sort();
crates.dedup();
crates.into_iter().collect()
}
/// Silly workaround for cyclic deps between the traits
@ -113,7 +115,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
source_root.resolve_path(path)
}
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> {
let _p = profile::span("relevant_crates");
let source_root = self.0.file_source_root(file_id);
self.0.source_root_crates(source_root)

View File

@ -29,7 +29,8 @@ smallvec.workspace = true
hashbrown.workspace = true
triomphe.workspace = true
rustc-dependencies.workspace = true
ra-ap-rustc_parse_format.workspace = true
ra-ap-rustc_abi.workspace = true
# local deps
stdx.workspace = true
@ -53,7 +54,7 @@ test-utils.workspace = true
test-fixture.workspace = true
[features]
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
in-rust-tree = []
[lints]
workspace = true
workspace = true

View File

@ -207,6 +207,13 @@ impl Attrs {
})
}
pub fn has_doc_notable_trait(&self) -> bool {
self.by_key("doc").tt_values().any(|tt| {
tt.delimiter.kind == DelimiterKind::Parenthesis &&
matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "notable_trait")
})
}
pub fn doc_exprs(&self) -> impl Iterator<Item = DocExpr> + '_ {
self.by_key("doc").tt_values().map(DocExpr::parse)
}
@ -355,7 +362,7 @@ fn parse_comma_sep<S>(subtree: &tt::Subtree<S>) -> Vec<SmolStr> {
}
impl AttrsWithOwner {
pub(crate) fn attrs_with_owner(db: &dyn DefDatabase, owner: AttrDefId) -> Self {
pub fn attrs_with_owner(db: &dyn DefDatabase, owner: AttrDefId) -> Self {
Self { attrs: db.attrs(owner), owner }
}

View File

@ -965,11 +965,10 @@ impl ExprCollector<'_> {
let res = match self.def_map.modules[module]
.scope
.macro_invocations
.get(&InFile::new(outer_file, self.ast_id_map.ast_id_for_ptr(syntax_ptr)))
.macro_invoc(InFile::new(outer_file, self.ast_id_map.ast_id_for_ptr(syntax_ptr)))
{
// fast path, macro call is in a block module
Some(&call) => Ok(self.expander.enter_expand_id(self.db, call)),
Some(call) => Ok(self.expander.enter_expand_id(self.db, call)),
None => self.expander.enter_expand(self.db, mcall, |path| {
self.def_map
.resolve_path(

View File

@ -92,7 +92,7 @@ impl ChildBySource for ItemScope {
self.impls().for_each(|imp| add_impl(db, res, file_id, imp));
self.extern_crate_decls().for_each(|ext| add_extern_crate(db, res, file_id, ext));
self.use_decls().for_each(|ext| add_use(db, res, file_id, ext));
self.unnamed_consts().for_each(|konst| {
self.unnamed_consts(db).for_each(|konst| {
let loc = konst.lookup(db);
if loc.id.file_id() == file_id {
res[keys::CONST].insert(loc.source(db).value, konst);

View File

@ -11,7 +11,7 @@ use hir_expand::{
};
use intern::Interned;
use la_arena::{Arena, ArenaMap};
use rustc_dependencies::abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
use syntax::ast::{self, HasName, HasVisibility};
use triomphe::Arc;

View File

@ -210,13 +210,10 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
#[salsa::invoke(AttrsWithOwner::attrs_query)]
fn attrs(&self, def: AttrDefId) -> Attrs;
#[salsa::transparent]
#[salsa::invoke(lang_item::lang_attr_query)]
fn lang_attr(&self, def: AttrDefId) -> Option<LangItem>;
#[salsa::transparent]
#[salsa::invoke(AttrsWithOwner::attrs_with_owner)]
fn attrs_with_owner(&self, def: AttrDefId) -> AttrsWithOwner;
// endregion:attrs
#[salsa::invoke(LangItems::lang_item_query)]
@ -240,7 +237,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
// endregion:visibilities
#[salsa::invoke(LangItems::crate_lang_items_query)]
fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;
fn crate_lang_items(&self, krate: CrateId) -> Option<Arc<LangItems>>;
fn crate_supports_no_std(&self, crate_id: CrateId) -> bool;
}

View File

@ -10,7 +10,7 @@ use crate::{
item_scope::ItemInNs,
nameres::DefMap,
path::{ModPath, PathKind},
visibility::Visibility,
visibility::{Visibility, VisibilityExplicity},
CrateRootModuleId, ModuleDefId, ModuleId,
};
@ -24,7 +24,7 @@ pub fn find_path(
prefer_prelude: bool,
) -> Option<ModPath> {
let _p = profile::span("find_path");
find_path_inner(db, item, from, None, prefer_no_std, prefer_prelude)
find_path_inner(FindPathCtx { db, prefixed: None, prefer_no_std, prefer_prelude }, item, from)
}
pub fn find_path_prefixed(
@ -36,7 +36,11 @@ pub fn find_path_prefixed(
prefer_prelude: bool,
) -> Option<ModPath> {
let _p = profile::span("find_path_prefixed");
find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std, prefer_prelude)
find_path_inner(
FindPathCtx { db, prefixed: Some(prefix_kind), prefer_no_std, prefer_prelude },
item,
from,
)
}
#[derive(Copy, Clone, Debug)]
@ -83,64 +87,60 @@ impl PrefixKind {
}
}
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
fn find_path_inner(
db: &dyn DefDatabase,
item: ItemInNs,
from: ModuleId,
#[derive(Copy, Clone)]
struct FindPathCtx<'db> {
db: &'db dyn DefDatabase,
prefixed: Option<PrefixKind>,
prefer_no_std: bool,
prefer_prelude: bool,
) -> Option<ModPath> {
}
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
// - if the item is a builtin, it's in scope
if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
}
let def_map = from.def_map(db);
let def_map = from.def_map(ctx.db);
let crate_root = def_map.crate_root();
// - if the item is a module, jump straight to module search
if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
let mut visited_modules = FxHashSet::default();
return find_path_for_module(
db,
FindPathCtx {
prefer_no_std: ctx.prefer_no_std || ctx.db.crate_supports_no_std(crate_root.krate),
..ctx
},
&def_map,
&mut visited_modules,
crate_root,
from,
module_id,
MAX_PATH_LEN,
prefixed,
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
prefer_prelude,
)
.map(|(item, _)| item);
}
// - if the item is already in scope, return the name under which it is
let scope_name = find_in_scope(db, &def_map, from, item);
if prefixed.is_none() {
let scope_name = find_in_scope(ctx.db, &def_map, from, item);
if ctx.prefixed.is_none() {
if let Some(scope_name) = scope_name {
return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
}
}
// - if the item is in the prelude, return the name from there
if let value @ Some(_) = find_in_prelude(db, &crate_root.def_map(db), &def_map, item, from) {
if let value @ Some(_) =
find_in_prelude(ctx.db, &crate_root.def_map(ctx.db), &def_map, item, from)
{
return value;
}
if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
// - if the item is an enum variant, refer to it via the enum
if let Some(mut path) = find_path_inner(
db,
ItemInNs::Types(variant.parent.into()),
from,
prefixed,
prefer_no_std,
prefer_prelude,
) {
let data = db.enum_data(variant.parent);
if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(variant.parent.into()), from) {
let data = ctx.db.enum_data(variant.parent);
path.push_segment(data.variants[variant.local_id].name.clone());
return Some(path);
}
@ -152,32 +152,29 @@ fn find_path_inner(
let mut visited_modules = FxHashSet::default();
calculate_best_path(
db,
FindPathCtx {
prefer_no_std: ctx.prefer_no_std || ctx.db.crate_supports_no_std(crate_root.krate),
..ctx
},
&def_map,
&mut visited_modules,
crate_root,
MAX_PATH_LEN,
item,
from,
prefixed,
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
prefer_prelude,
scope_name,
)
.map(|(item, _)| item)
}
fn find_path_for_module(
db: &dyn DefDatabase,
ctx: FindPathCtx<'_>,
def_map: &DefMap,
visited_modules: &mut FxHashSet<ModuleId>,
crate_root: CrateRootModuleId,
from: ModuleId,
module_id: ModuleId,
max_len: usize,
prefixed: Option<PrefixKind>,
prefer_no_std: bool,
prefer_prelude: bool,
) -> Option<(ModPath, Stability)> {
if max_len == 0 {
return None;
@ -185,8 +182,8 @@ fn find_path_for_module(
// Base cases:
// - if the item is already in scope, return the name under which it is
let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into()));
if prefixed.is_none() {
let scope_name = find_in_scope(ctx.db, def_map, from, ItemInNs::Types(module_id.into()));
if ctx.prefixed.is_none() {
if let Some(scope_name) = scope_name {
return Some((ModPath::from_segments(PathKind::Plain, Some(scope_name)), Stable));
}
@ -198,20 +195,20 @@ fn find_path_for_module(
}
// - if relative paths are fine, check if we are searching for a parent
if prefixed.filter(PrefixKind::is_absolute).is_none() {
if ctx.prefixed.filter(PrefixKind::is_absolute).is_none() {
if let modpath @ Some(_) = find_self_super(def_map, module_id, from) {
return modpath.zip(Some(Stable));
}
}
// - if the item is the crate root of a dependency crate, return the name from the extern prelude
let root_def_map = crate_root.def_map(db);
let root_def_map = crate_root.def_map(ctx.db);
for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude() {
if module_id == def_id {
let name = scope_name.unwrap_or_else(|| name.clone());
let name_already_occupied_in_type_ns = def_map
.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
.with_ancestor_maps(ctx.db, from.local_id, &mut |def_map, local_id| {
def_map[local_id]
.scope
.type_(&name)
@ -229,21 +226,18 @@ fn find_path_for_module(
}
if let value @ Some(_) =
find_in_prelude(db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
find_in_prelude(ctx.db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
{
return value.zip(Some(Stable));
}
calculate_best_path(
db,
ctx,
def_map,
visited_modules,
crate_root,
max_len,
ItemInNs::Types(module_id.into()),
from,
prefixed,
prefer_no_std,
prefer_prelude,
scope_name,
)
}
@ -256,7 +250,7 @@ fn find_in_scope(
item: ItemInNs,
) -> Option<Name> {
def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
def_map[local_id].scope.name_of(item).map(|(name, _, _)| name.clone())
})
}
@ -273,7 +267,7 @@ fn find_in_prelude(
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
let prelude_def_map = prelude_module.def_map(db);
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
let (name, vis) = prelude_scope.name_of(item)?;
let (name, vis, _declared) = prelude_scope.name_of(item)?;
if !vis.is_visible_from(db, from) {
return None;
}
@ -315,16 +309,13 @@ fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<M
}
fn calculate_best_path(
db: &dyn DefDatabase,
ctx: FindPathCtx<'_>,
def_map: &DefMap,
visited_modules: &mut FxHashSet<ModuleId>,
crate_root: CrateRootModuleId,
max_len: usize,
item: ItemInNs,
from: ModuleId,
mut prefixed: Option<PrefixKind>,
prefer_no_std: bool,
prefer_prelude: bool,
scope_name: Option<Name>,
) -> Option<(ModPath, Stability)> {
if max_len <= 1 {
@ -341,32 +332,29 @@ fn calculate_best_path(
};
// Recursive case:
// - otherwise, look for modules containing (reexporting) it and import it from one of those
if item.krate(db) == Some(from.krate) {
if item.krate(ctx.db) == Some(from.krate) {
let mut best_path_len = max_len;
// Item was defined in the same crate that wants to import it. It cannot be found in any
// dependency in this case.
for (module_id, name) in find_local_import_locations(db, item, from) {
for (module_id, name) in find_local_import_locations(ctx.db, item, from) {
if !visited_modules.insert(module_id) {
cov_mark::hit!(recursive_imports);
continue;
}
if let Some(mut path) = find_path_for_module(
db,
ctx,
def_map,
visited_modules,
crate_root,
from,
module_id,
best_path_len - 1,
prefixed,
prefer_no_std,
prefer_prelude,
) {
path.0.push_segment(name);
let new_path = match best_path.take() {
Some(best_path) => {
select_best_path(best_path, path, prefer_no_std, prefer_prelude)
select_best_path(best_path, path, ctx.prefer_no_std, ctx.prefer_prelude)
}
None => path,
};
@ -379,8 +367,8 @@ fn calculate_best_path(
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
// that wants to import it here, but we always prefer to use the external path here.
for dep in &db.crate_graph()[from.krate].dependencies {
let import_map = db.import_map(dep.crate_id);
for dep in &ctx.db.crate_graph()[from.krate].dependencies {
let import_map = ctx.db.import_map(dep.crate_id);
let Some(import_info_for) = import_map.import_info_for(item) else { continue };
for info in import_info_for {
if info.is_doc_hidden {
@ -391,16 +379,13 @@ fn calculate_best_path(
// 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?
let Some((mut path, path_stability)) = find_path_for_module(
db,
ctx,
def_map,
visited_modules,
crate_root,
from,
info.container,
max_len - 1,
prefixed,
prefer_no_std,
prefer_prelude,
) else {
continue;
};
@ -413,17 +398,21 @@ fn calculate_best_path(
);
let new_path_with_stab = match best_path.take() {
Some(best_path) => {
select_best_path(best_path, path_with_stab, prefer_no_std, prefer_prelude)
}
Some(best_path) => select_best_path(
best_path,
path_with_stab,
ctx.prefer_no_std,
ctx.prefer_prelude,
),
None => path_with_stab,
};
update_best_path(&mut best_path, new_path_with_stab);
}
}
}
if let Some(module) = item.module(db) {
if module.containing_block().is_some() && prefixed.is_some() {
let mut prefixed = ctx.prefixed;
if let Some(module) = item.module(ctx.db) {
if module.containing_block().is_some() && ctx.prefixed.is_some() {
cov_mark::hit!(prefixed_in_block_expression);
prefixed = Some(PrefixKind::Plain);
}
@ -548,34 +537,35 @@ fn find_local_import_locations(
&ext_def_map[module.local_id]
};
if let Some((name, vis)) = data.scope.name_of(item) {
if let Some((name, vis, declared)) = data.scope.name_of(item) {
if vis.is_visible_from(db, from) {
let is_private = match vis {
Visibility::Module(private_to) => private_to.local_id == module.local_id,
Visibility::Public => false,
};
let is_original_def = match item.as_module_def_id() {
Some(module_def_id) => data.scope.declarations().any(|it| it == module_def_id),
None => false,
let is_pub_or_explicit = match vis {
Visibility::Module(_, VisibilityExplicity::Explicit) => {
cov_mark::hit!(explicit_private_imports);
true
}
Visibility::Module(_, VisibilityExplicity::Implicit) => {
cov_mark::hit!(discount_private_imports);
false
}
Visibility::Public => true,
};
// Ignore private imports. these could be used if we are
// Ignore private imports unless they are explicit. these could be used if we are
// in a submodule of this module, but that's usually not
// what the user wants; and if this module can import
// the item and we're a submodule of it, so can we.
// Also this keeps the cached data smaller.
if !is_private || is_original_def {
if is_pub_or_explicit || declared {
locations.push((module, name.clone()));
}
}
}
// Descend into all modules visible from `from`.
for (ty, vis) in data.scope.types() {
if let ModuleDefId::ModuleId(module) = ty {
if vis.is_visible_from(db, from) {
worklist.push(module);
}
for (module, vis) in data.scope.modules_in_scope() {
if vis.is_visible_from(db, from) {
worklist.push(module);
}
}
}
@ -625,16 +615,14 @@ mod tests {
.expect("path does not resolve to a type");
let found_path = find_path_inner(
&db,
FindPathCtx { prefer_no_std: false, db: &db, prefixed: prefix_kind, prefer_prelude },
ItemInNs::Types(resolved),
module,
prefix_kind,
false,
prefer_prelude,
);
assert_eq!(found_path, Some(mod_path), "on kind: {prefix_kind:?}");
}
#[track_caller]
fn check_found_path(
ra_fixture: &str,
unprefixed: &str,
@ -1004,6 +992,7 @@ pub use crate::foo::bar::S;
#[test]
fn discount_private_imports() {
cov_mark::check!(discount_private_imports);
check_found_path(
r#"
//- /main.rs
@ -1021,6 +1010,47 @@ $0
);
}
#[test]
fn explicit_private_imports_crate() {
cov_mark::check!(explicit_private_imports);
check_found_path(
r#"
//- /main.rs
mod foo;
pub mod bar { pub struct S; }
pub(crate) use bar::S;
//- /foo.rs
$0
"#,
"crate::S",
"crate::S",
"crate::S",
"crate::S",
);
}
#[test]
fn explicit_private_imports() {
cov_mark::check!(explicit_private_imports);
check_found_path(
r#"
//- /main.rs
pub mod bar {
mod foo;
pub mod baz { pub struct S; }
pub(self) use baz::S;
}
//- /bar/foo.rs
$0
"#,
"super::S",
"super::S",
"crate::bar::S",
"super::S",
);
}
#[test]
fn import_cycle() {
check_found_path(

View File

@ -107,11 +107,11 @@ impl TypeOrConstParamData {
impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
/// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct GenericParams {
pub type_or_consts: Arena<TypeOrConstParamData>,
pub lifetimes: Arena<LifetimeParamData>,
pub where_predicates: Vec<WherePredicate>,
pub where_predicates: Box<[WherePredicate]>,
}
/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
@ -142,109 +142,14 @@ pub enum WherePredicateTypeTarget {
TypeOrConstParam(LocalTypeOrConstParamId),
}
impl GenericParams {
/// Iterator of type_or_consts field
pub fn iter(
&self,
) -> impl DoubleEndedIterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
self.type_or_consts.iter()
}
pub(crate) fn generic_params_query(
db: &dyn DefDatabase,
def: GenericDefId,
) -> Interned<GenericParams> {
let _p = profile::span("generic_params_query");
let krate = def.module(db).krate;
let cfg_options = db.crate_graph();
let cfg_options = &cfg_options[krate].cfg_options;
// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
// Therefore, make a first pass to check if all parameters are enabled and, if so,
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
let all_type_or_consts_enabled =
params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
Interned::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
params
.type_or_consts
.iter()
.filter_map(|(idx, param)| {
enabled(idx.into()).then(|| param.clone())
})
.collect()
}),
lifetimes: all_lifetimes_enabled
.then(|| params.lifetimes.clone())
.unwrap_or_else(|| {
params
.lifetimes
.iter()
.filter_map(|(idx, param)| {
enabled(idx.into()).then(|| param.clone())
})
.collect()
}),
where_predicates: params.where_predicates.clone(),
})
}
};
macro_rules! id_to_generics {
($id:ident) => {{
let id = $id.lookup(db).id;
let tree = id.item_tree(db);
let item = &tree[id.value];
enabled_params(&item.generic_params, &tree)
}};
}
match def {
GenericDefId::FunctionId(id) => {
let loc = id.lookup(db);
let tree = loc.id.item_tree(db);
let item = &tree[loc.id.value];
let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
let mut generic_params = GenericParams::clone(&enabled_params);
let module = loc.container.module(db);
let func_data = db.function_data(id);
// Don't create an `Expander` if not needed since this
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
let mut expander =
Lazy::new(|| (module.def_map(db), Expander::new(db, loc.id.file_id(), module)));
for param in func_data.params.iter() {
generic_params.fill_implicit_impl_trait_args(db, &mut expander, param);
}
Interned::new(generic_params)
}
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics!(id),
GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics!(id),
GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics!(id),
GenericDefId::TraitId(id) => id_to_generics!(id),
GenericDefId::TraitAliasId(id) => id_to_generics!(id),
GenericDefId::TypeAliasId(id) => id_to_generics!(id),
GenericDefId::ImplId(id) => id_to_generics!(id),
GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
Interned::new(GenericParams::default())
}
}
}
#[derive(Clone, Default)]
pub(crate) struct GenericParamsCollector {
pub(crate) type_or_consts: Arena<TypeOrConstParamData>,
lifetimes: Arena<LifetimeParamData>,
where_predicates: Vec<WherePredicate>,
}
impl GenericParamsCollector {
pub(crate) fn fill(
&mut self,
lower_ctx: &LowerCtx<'_>,
@ -444,11 +349,131 @@ impl GenericParams {
});
}
pub(crate) fn shrink_to_fit(&mut self) {
let Self { lifetimes, type_or_consts: types, where_predicates } = self;
pub(crate) fn finish(self) -> GenericParams {
let Self { mut lifetimes, mut type_or_consts, where_predicates } = self;
lifetimes.shrink_to_fit();
types.shrink_to_fit();
where_predicates.shrink_to_fit();
type_or_consts.shrink_to_fit();
GenericParams {
type_or_consts,
lifetimes,
where_predicates: where_predicates.into_boxed_slice(),
}
}
}
impl GenericParams {
/// Iterator of type_or_consts field
pub fn iter(
&self,
) -> impl DoubleEndedIterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
self.type_or_consts.iter()
}
pub(crate) fn generic_params_query(
db: &dyn DefDatabase,
def: GenericDefId,
) -> Interned<GenericParams> {
let _p = profile::span("generic_params_query");
let krate = def.module(db).krate;
let cfg_options = db.crate_graph();
let cfg_options = &cfg_options[krate].cfg_options;
// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
// Therefore, make a first pass to check if all parameters are enabled and, if so,
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
let all_type_or_consts_enabled =
params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
Interned::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
params
.type_or_consts
.iter()
.filter_map(|(idx, param)| {
enabled(idx.into()).then(|| param.clone())
})
.collect()
}),
lifetimes: all_lifetimes_enabled
.then(|| params.lifetimes.clone())
.unwrap_or_else(|| {
params
.lifetimes
.iter()
.filter_map(|(idx, param)| {
enabled(idx.into()).then(|| param.clone())
})
.collect()
}),
where_predicates: params.where_predicates.clone(),
})
}
};
macro_rules! id_to_generics {
($id:ident) => {{
let id = $id.lookup(db).id;
let tree = id.item_tree(db);
let item = &tree[id.value];
enabled_params(&item.generic_params, &tree)
}};
}
match def {
GenericDefId::FunctionId(id) => {
let loc = id.lookup(db);
let tree = loc.id.item_tree(db);
let item = &tree[loc.id.value];
let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
let module = loc.container.module(db);
let func_data = db.function_data(id);
if func_data.params.is_empty() {
enabled_params
} else {
let mut generic_params = GenericParamsCollector {
type_or_consts: enabled_params.type_or_consts.clone(),
lifetimes: enabled_params.lifetimes.clone(),
where_predicates: enabled_params.where_predicates.clone().into(),
};
// Don't create an `Expander` if not needed since this
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
let mut expander = Lazy::new(|| {
(module.def_map(db), Expander::new(db, loc.id.file_id(), module))
});
for param in func_data.params.iter() {
generic_params.fill_implicit_impl_trait_args(db, &mut expander, param);
}
Interned::new(generic_params.finish())
}
}
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics!(id),
GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics!(id),
GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics!(id),
GenericDefId::TraitId(id) => id_to_generics!(id),
GenericDefId::TraitAliasId(id) => id_to_generics!(id),
GenericDefId::TypeAliasId(id) => id_to_generics!(id),
GenericDefId::ImplId(id) => id_to_generics!(id),
GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
Interned::new(GenericParams {
type_or_consts: Default::default(),
lifetimes: Default::default(),
where_predicates: Default::default(),
})
}
}
}
pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {

View File

@ -2,7 +2,7 @@
use std::mem;
use hir_expand::name::Name;
use rustc_dependencies::parse_format as parse;
use rustc_parse_format as parse;
use stdx::TupleExt;
use syntax::{
ast::{self, IsString},

View File

@ -116,8 +116,7 @@ pub enum TypeRef {
Path(Path),
RawPtr(Box<TypeRef>, Mutability),
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
// FIXME: for full const generics, the latter element (length) here is going to have to be an
// expression that is further lowered later in hir_ty.
// FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>),
Array(Box<TypeRef>, ConstRef),
Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type.

View File

@ -15,9 +15,11 @@ use stdx::format_to;
use syntax::ast;
use crate::{
db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId,
ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId,
TraitId, UseId,
db::DefDatabase,
per_ns::PerNs,
visibility::{Visibility, VisibilityExplicity},
AdtId, BuiltinType, ConstId, ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId,
ModuleDefId, ModuleId, TraitId, UseId,
};
#[derive(Debug, Default)]
@ -105,7 +107,7 @@ pub struct ItemScope {
/// The attribute macro invocations in this scope.
attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
/// The macro invocations in this scope.
pub macro_invocations: FxHashMap<AstId<ast::MacroCall>, MacroCallId>,
macro_invocations: FxHashMap<AstId<ast::MacroCall>, MacroCallId>,
/// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes
/// paired with the derive macro invocations for the specific attribute.
derive_macros: FxHashMap<AstId<ast::Adt>, SmallVec<[DeriveMacroInvocation; 1]>>,
@ -145,8 +147,8 @@ impl ItemScope {
.chain(self.values.keys())
.chain(self.macros.keys())
.chain(self.unresolved.iter())
.unique()
.sorted()
.dedup()
.map(move |name| (name, self.get(name)))
}
@ -157,8 +159,8 @@ impl ItemScope {
.filter_map(ImportOrExternCrate::into_import)
.chain(self.use_imports_values.keys().copied())
.chain(self.use_imports_macros.keys().copied())
.unique()
.sorted()
.dedup()
}
pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs {
@ -234,20 +236,37 @@ impl ItemScope {
self.impls.iter().copied()
}
pub fn values(
&self,
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
self.values.values().copied().map(|(a, b, _)| (a, b))
pub(crate) fn modules_in_scope(&self) -> impl Iterator<Item = (ModuleId, Visibility)> + '_ {
self.types.values().copied().filter_map(|(def, vis, _)| match def {
ModuleDefId::ModuleId(module) => Some((module, vis)),
_ => None,
})
}
pub(crate) fn types(
&self,
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
self.types.values().copied().map(|(def, vis, _)| (def, vis))
}
pub fn unnamed_consts<'a>(
&'a self,
db: &'a dyn DefDatabase,
) -> impl Iterator<Item = ConstId> + 'a {
// FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those.
// Should be removed once synstructure stops doing that.
let synstructure_hack_consts = self.values.values().filter_map(|(item, _, _)| match item {
&ModuleDefId::ConstId(id) => {
let loc = id.lookup(db);
let item_tree = loc.id.item_tree(db);
if item_tree[loc.id.value]
.name
.as_ref()
.map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_"))
{
Some(id)
} else {
None
}
}
_ => None,
});
pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
self.unnamed_consts.iter().copied()
self.unnamed_consts.iter().copied().chain(synstructure_hack_consts)
}
/// Iterate over all module scoped macros
@ -274,21 +293,18 @@ impl ItemScope {
}
/// XXX: this is O(N) rather than O(1), try to not introduce new usages.
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility, /*declared*/ bool)> {
match item {
ItemInNs::Macros(def) => self
.macros
.iter()
.find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
ItemInNs::Types(def) => self
.types
.iter()
.find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
ItemInNs::Macros(def) => self.macros.iter().find_map(|(name, &(other_def, vis, i))| {
(other_def == def).then_some((name, vis, i.is_none()))
}),
ItemInNs::Types(def) => self.types.iter().find_map(|(name, &(other_def, vis, i))| {
(other_def == def).then_some((name, vis, i.is_none()))
}),
ItemInNs::Values(def) => self
.values
.iter()
.find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
ItemInNs::Values(def) => self.values.iter().find_map(|(name, &(other_def, vis, i))| {
(other_def == def).then_some((name, vis, i.is_none()))
}),
}
}
@ -316,6 +332,10 @@ impl ItemScope {
}),
)
}
pub(crate) fn macro_invoc(&self, call: AstId<ast::MacroCall>) -> Option<MacroCallId> {
self.macro_invocations.get(&call).copied()
}
}
impl ItemScope {
@ -624,18 +644,17 @@ impl ItemScope {
pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
self.types
.values_mut()
.map(|(def, vis, _)| (def, vis))
.chain(self.values.values_mut().map(|(def, vis, _)| (def, vis)))
.map(|(_, v)| v)
.map(|(_, vis, _)| vis)
.chain(self.values.values_mut().map(|(_, vis, _)| vis))
.chain(self.unnamed_trait_imports.values_mut().map(|(vis, _)| vis))
.for_each(|vis| *vis = Visibility::Module(this_module));
.for_each(|vis| *vis = Visibility::Module(this_module, VisibilityExplicity::Implicit));
for (mac, vis, import) in self.macros.values_mut() {
if matches!(mac, MacroId::ProcMacroId(_) if import.is_none()) {
continue;
}
*vis = Visibility::Module(this_module);
*vis = Visibility::Module(this_module, VisibilityExplicity::Implicit);
}
}

View File

@ -69,7 +69,7 @@ use crate::{
generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
visibility::RawVisibility,
visibility::{RawVisibility, VisibilityExplicity},
BlockId, Lookup,
};
@ -78,8 +78,9 @@ pub struct RawVisibilityId(u32);
impl RawVisibilityId {
pub const PUB: Self = RawVisibilityId(u32::max_value());
pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1);
pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2);
pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::max_value() - 1);
pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::max_value() - 2);
pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 3);
}
impl fmt::Debug for RawVisibilityId {
@ -87,7 +88,7 @@ impl fmt::Debug for RawVisibilityId {
let mut f = f.debug_tuple("RawVisibilityId");
match *self {
Self::PUB => f.field(&"pub"),
Self::PRIV => f.field(&"pub(self)"),
Self::PRIV_IMPLICIT | Self::PRIV_EXPLICIT => f.field(&"pub(self)"),
Self::PUB_CRATE => f.field(&"pub(crate)"),
_ => f.field(&self.0),
};
@ -249,19 +250,30 @@ impl ItemVisibilities {
fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
match &vis {
RawVisibility::Public => RawVisibilityId::PUB,
RawVisibility::Module(path) if path.segments().is_empty() => match &path.kind {
PathKind::Super(0) => RawVisibilityId::PRIV,
PathKind::Crate => RawVisibilityId::PUB_CRATE,
_ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
},
RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => {
match (&path.kind, explicitiy) {
(PathKind::Super(0), VisibilityExplicity::Explicit) => {
RawVisibilityId::PRIV_EXPLICIT
}
(PathKind::Super(0), VisibilityExplicity::Implicit) => {
RawVisibilityId::PRIV_IMPLICIT
}
(PathKind::Crate, _) => RawVisibilityId::PUB_CRATE,
_ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
}
}
_ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
}
}
}
static VIS_PUB: RawVisibility = RawVisibility::Public;
static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)));
static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate));
static VIS_PRIV_IMPLICIT: RawVisibility =
RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicity::Implicit);
static VIS_PRIV_EXPLICIT: RawVisibility =
RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicity::Explicit);
static VIS_PUB_CRATE: RawVisibility =
RawVisibility::Module(ModPath::from_kind(PathKind::Crate), VisibilityExplicity::Explicit);
#[derive(Default, Debug, Eq, PartialEq)]
struct ItemTreeData {
@ -540,7 +552,8 @@ impl Index<RawVisibilityId> for ItemTree {
type Output = RawVisibility;
fn index(&self, index: RawVisibilityId) -> &Self::Output {
match index {
RawVisibilityId::PRIV => &VIS_PRIV,
RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT,
RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT,
RawVisibilityId::PUB => &VIS_PUB,
RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
_ => &self.data().vis.arena[Idx::from_raw(index.0.into())],

View File

@ -6,7 +6,7 @@ use hir_expand::{ast_id_map::AstIdMap, span_map::SpanMapRef, HirFileId};
use syntax::ast::{self, HasModuleItem, HasTypeBounds};
use crate::{
generics::{GenericParams, TypeParamData, TypeParamProvenance},
generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef},
LocalLifetimeParamId, LocalTypeOrConstParamId,
};
@ -386,17 +386,16 @@ impl<'a> Ctx<'a> {
flags |= FnFlags::HAS_UNSAFE_KW;
}
let mut res = Function {
let res = Function {
name,
visibility,
explicit_generic_params: Interned::new(GenericParams::default()),
explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func),
abi,
params,
ret_type: Interned::new(ret_type),
ast_id,
flags,
};
res.explicit_generic_params = self.lower_generic_params(HasImplicitSelf::No, func);
Some(id(self.data().functions.alloc(res)))
}
@ -604,7 +603,7 @@ impl<'a> Ctx<'a> {
has_implicit_self: HasImplicitSelf,
node: &dyn ast::HasGenericParams,
) -> Interned<GenericParams> {
let mut generics = GenericParams::default();
let mut generics = GenericParamsCollector::default();
if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
// Traits and trait aliases get the Self type as an implicit first type parameter.
@ -642,8 +641,7 @@ impl<'a> Ctx<'a> {
};
generics.fill(&self.body_ctx, node, add_param_attrs);
generics.shrink_to_fit();
Interned::new(generics)
Interned::new(generics.finish())
}
fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<TypeBound>]> {

View File

@ -104,7 +104,9 @@ impl Printer<'_> {
fn print_visibility(&mut self, vis: RawVisibilityId) {
match &self.tree[vis] {
RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db.upcast())),
RawVisibility::Module(path, _expl) => {
w!(self, "pub({}) ", path.display(self.db.upcast()))
}
RawVisibility::Public => w!(self, "pub "),
};
}

View File

@ -87,7 +87,10 @@ impl LangItems {
}
/// Salsa query. This will look for lang items in a specific crate.
pub(crate) fn crate_lang_items_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<LangItems> {
pub(crate) fn crate_lang_items_query(
db: &dyn DefDatabase,
krate: CrateId,
) -> Option<Arc<LangItems>> {
let _p = profile::span("crate_lang_items_query");
let mut lang_items = LangItems::default();
@ -150,7 +153,11 @@ impl LangItems {
}
}
Arc::new(lang_items)
if lang_items.items.is_empty() {
None
} else {
Some(Arc::new(lang_items))
}
}
/// Salsa query. Look for a lang item, starting from the specified crate and recursively
@ -161,9 +168,9 @@ impl LangItems {
item: LangItem,
) -> Option<LangItemTarget> {
let _p = profile::span("lang_item_query");
let lang_items = db.crate_lang_items(start_crate);
let start_crate_target = lang_items.items.get(&item);
if let Some(&target) = start_crate_target {
if let Some(target) =
db.crate_lang_items(start_crate).and_then(|it| it.items.get(&item).copied())
{
return Some(target);
}
db.crate_graph()[start_crate]

View File

@ -10,10 +10,17 @@
#![warn(rust_2018_idioms, unused_lifetimes)]
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#[allow(unused)]
macro_rules! eprintln {
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
}
#[cfg(feature = "in-rust-tree")]
extern crate rustc_parse_format;
#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_parse_format as rustc_parse_format;
#[cfg(feature = "in-rust-tree")]
extern crate rustc_abi;
#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_abi as rustc_abi;
pub mod db;
@ -49,7 +56,7 @@ pub mod visibility;
pub mod find_path;
pub mod import_map;
pub use rustc_dependencies::abi as layout;
pub use rustc_abi as layout;
use triomphe::Arc;
#[cfg(test)]

View File

@ -16,13 +16,12 @@ struct Foo;
#[derive(Copy)]
struct Foo;
impl < > core::marker::Copy for Foo< > where {}"#]],
impl < > $crate::marker::Copy for Foo< > where {}"#]],
);
}
#[test]
fn test_copy_expand_in_core() {
cov_mark::check!(test_copy_expand_in_core);
check(
r#"
//- /lib.rs crate:core
@ -41,7 +40,7 @@ macro Copy {}
#[derive(Copy)]
struct Foo;
impl < > crate ::marker::Copy for Foo< > where {}"#]],
impl < > $crate::marker::Copy for Foo< > where {}"#]],
);
}
@ -57,7 +56,7 @@ struct Foo<A, B>;
#[derive(Copy)]
struct Foo<A, B>;
impl <A: core::marker::Copy, B: core::marker::Copy, > core::marker::Copy for Foo<A, B, > where {}"#]],
impl <A: $crate::marker::Copy, B: $crate::marker::Copy, > $crate::marker::Copy for Foo<A, B, > where {}"#]],
);
}
@ -74,7 +73,7 @@ struct Foo<A, B, 'a, 'b>;
#[derive(Copy)]
struct Foo<A, B, 'a, 'b>;
impl <A: core::marker::Copy, B: core::marker::Copy, > core::marker::Copy for Foo<A, B, > where {}"#]],
impl <A: $crate::marker::Copy, B: $crate::marker::Copy, > $crate::marker::Copy for Foo<A, B, > where {}"#]],
);
}
@ -98,7 +97,7 @@ enum Command<A, B> {
Jump,
}
impl <A: core::clone::Clone, B: core::clone::Clone, > core::clone::Clone for Command<A, B, > where {
impl <A: $crate::clone::Clone, B: $crate::clone::Clone, > $crate::clone::Clone for Command<A, B, > where {
fn clone(&self ) -> Self {
match self {
Command::Move {
@ -158,7 +157,7 @@ where
generic: Vec<T::InGenericArg>,
}
impl <T: core::clone::Clone, > core::clone::Clone for Foo<T, > where T: Trait, T::InFieldShorthand: core::clone::Clone, T::InGenericArg: core::clone::Clone, {
impl <T: $crate::clone::Clone, > $crate::clone::Clone for Foo<T, > where T: Trait, T::InFieldShorthand: $crate::clone::Clone, T::InGenericArg: $crate::clone::Clone, {
fn clone(&self ) -> Self {
match self {
Foo {
@ -186,7 +185,7 @@ struct Foo<const X: usize, T>(u32);
#[derive(Clone)]
struct Foo<const X: usize, T>(u32);
impl <const X: usize, T: core::clone::Clone, > core::clone::Clone for Foo<X, T, > where {
impl <const X: usize, T: $crate::clone::Clone, > $crate::clone::Clone for Foo<X, T, > where {
fn clone(&self ) -> Self {
match self {
Foo(f0, )=>Foo(f0.clone(), ),
@ -226,14 +225,14 @@ enum Bar {
Bar,
}
impl < > core::default::Default for Foo< > where {
impl < > $crate::default::Default for Foo< > where {
fn default() -> Self {
Foo {
field1: core::default::Default::default(), field2: core::default::Default::default(),
field1: $crate::default::Default::default(), field2: $crate::default::Default::default(),
}
}
}
impl < > core::default::Default for Bar< > where {
impl < > $crate::default::Default for Bar< > where {
fn default() -> Self {
Bar::Bar
}
@ -261,7 +260,7 @@ enum Command {
Jump,
}
impl < > core::cmp::PartialEq for Command< > where {
impl < > $crate::cmp::PartialEq for Command< > where {
fn eq(&self , other: &Self ) -> bool {
match (self , other) {
(Command::Move {
@ -274,7 +273,7 @@ impl < > core::cmp::PartialEq for Command< > where {
}
}
}
impl < > core::cmp::Eq for Command< > where {}"#]],
impl < > $crate::cmp::Eq for Command< > where {}"#]],
);
}
@ -299,7 +298,7 @@ enum Command {
Jump,
}
impl < > core::cmp::PartialEq for Command< > where {
impl < > $crate::cmp::PartialEq for Command< > where {
fn eq(&self , other: &Self ) -> bool {
match (self , other) {
(Command::Move {
@ -312,7 +311,7 @@ impl < > core::cmp::PartialEq for Command< > where {
}
}
}
impl < > core::cmp::Eq for Command< > where {}"#]],
impl < > $crate::cmp::Eq for Command< > where {}"#]],
);
}
@ -336,10 +335,10 @@ enum Command {
Jump,
}
impl < > core::cmp::PartialOrd for Command< > where {
fn partial_cmp(&self , other: &Self ) -> core::option::Option::Option<core::cmp::Ordering> {
match core::intrinsics::discriminant_value(self ).partial_cmp(&core::intrinsics::discriminant_value(other)) {
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
impl < > $crate::cmp::PartialOrd for Command< > where {
fn partial_cmp(&self , other: &Self ) -> $crate::option::Option::Option<$crate::cmp::Ordering> {
match $crate::intrinsics::discriminant_value(self ).partial_cmp(&$crate::intrinsics::discriminant_value(other)) {
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
match (self , other) {
(Command::Move {
x: x_self, y: y_self,
@ -348,10 +347,10 @@ impl < > core::cmp::PartialOrd for Command< > where {
x: x_other, y: y_other,
}
)=>match x_self.partial_cmp(&x_other) {
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
match y_self.partial_cmp(&y_other) {
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
core::option::Option::Some(core::cmp::Ordering::Equal)
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
$crate::option::Option::Some($crate::cmp::Ordering::Equal)
}
c=>return c,
}
@ -359,22 +358,22 @@ impl < > core::cmp::PartialOrd for Command< > where {
c=>return c,
}
, (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.partial_cmp(&f0_other) {
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
core::option::Option::Some(core::cmp::Ordering::Equal)
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
$crate::option::Option::Some($crate::cmp::Ordering::Equal)
}
c=>return c,
}
, (Command::Jump, Command::Jump)=>core::option::Option::Some(core::cmp::Ordering::Equal), _unused=>core::option::Option::Some(core::cmp::Ordering::Equal)
, (Command::Jump, Command::Jump)=>$crate::option::Option::Some($crate::cmp::Ordering::Equal), _unused=>$crate::option::Option::Some($crate::cmp::Ordering::Equal)
}
}
c=>return c,
}
}
}
impl < > core::cmp::Ord for Command< > where {
fn cmp(&self , other: &Self ) -> core::cmp::Ordering {
match core::intrinsics::discriminant_value(self ).cmp(&core::intrinsics::discriminant_value(other)) {
core::cmp::Ordering::Equal=> {
impl < > $crate::cmp::Ord for Command< > where {
fn cmp(&self , other: &Self ) -> $crate::cmp::Ordering {
match $crate::intrinsics::discriminant_value(self ).cmp(&$crate::intrinsics::discriminant_value(other)) {
$crate::cmp::Ordering::Equal=> {
match (self , other) {
(Command::Move {
x: x_self, y: y_self,
@ -383,10 +382,10 @@ impl < > core::cmp::Ord for Command< > where {
x: x_other, y: y_other,
}
)=>match x_self.cmp(&x_other) {
core::cmp::Ordering::Equal=> {
$crate::cmp::Ordering::Equal=> {
match y_self.cmp(&y_other) {
core::cmp::Ordering::Equal=> {
core::cmp::Ordering::Equal
$crate::cmp::Ordering::Equal=> {
$crate::cmp::Ordering::Equal
}
c=>return c,
}
@ -394,12 +393,12 @@ impl < > core::cmp::Ord for Command< > where {
c=>return c,
}
, (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.cmp(&f0_other) {
core::cmp::Ordering::Equal=> {
core::cmp::Ordering::Equal
$crate::cmp::Ordering::Equal=> {
$crate::cmp::Ordering::Equal
}
c=>return c,
}
, (Command::Jump, Command::Jump)=>core::cmp::Ordering::Equal, _unused=>core::cmp::Ordering::Equal
, (Command::Jump, Command::Jump)=>$crate::cmp::Ordering::Equal, _unused=>$crate::cmp::Ordering::Equal
}
}
c=>return c,
@ -433,8 +432,8 @@ struct Foo {
z: (i32, u64),
}
impl < > core::hash::Hash for Foo< > where {
fn hash<H: core::hash::Hasher>(&self , ra_expand_state: &mut H) {
impl < > $crate::hash::Hash for Foo< > where {
fn hash<H: $crate::hash::Hasher>(&self , ra_expand_state: &mut H) {
match self {
Foo {
x: x, y: y, z: z,
@ -471,9 +470,9 @@ enum Command {
Jump,
}
impl < > core::hash::Hash for Command< > where {
fn hash<H: core::hash::Hasher>(&self , ra_expand_state: &mut H) {
core::mem::discriminant(self ).hash(ra_expand_state);
impl < > $crate::hash::Hash for Command< > where {
fn hash<H: $crate::hash::Hasher>(&self , ra_expand_state: &mut H) {
$crate::mem::discriminant(self ).hash(ra_expand_state);
match self {
Command::Move {
x: x, y: y,
@ -517,8 +516,8 @@ enum Command {
Jump,
}
impl < > core::fmt::Debug for Command< > where {
fn fmt(&self , f: &mut core::fmt::Formatter) -> core::fmt::Result {
impl < > $crate::fmt::Debug for Command< > where {
fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
match self {
Command::Move {
x: x, y: y,

View File

@ -136,7 +136,7 @@ fn main() { option_env!("TEST_ENV_VAR"); }
#[rustc_builtin_macro]
macro_rules! option_env {() => {}}
fn main() { ::core::option::Option::None:: < &str>; }
fn main() { $crate::option::Option::None:: < &str>; }
"#]],
);
}

View File

@ -79,7 +79,7 @@ use crate::{
nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
path::ModPath,
per_ns::PerNs,
visibility::Visibility,
visibility::{Visibility, VisibilityExplicity},
AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, LocalModuleId, Lookup,
MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
};
@ -332,7 +332,10 @@ impl DefMap {
// NB: we use `None` as block here, which would be wrong for implicit
// modules declared by blocks with items. At the moment, we don't use
// this visibility for anything outside IDE, so that's probably OK.
let visibility = Visibility::Module(ModuleId { krate, local_id, block: None });
let visibility = Visibility::Module(
ModuleId { krate, local_id, block: None },
VisibilityExplicity::Implicit,
);
let module_data = ModuleData::new(
ModuleOrigin::BlockExpr { block: block.ast_id, id: block_id },
visibility,

View File

@ -87,7 +87,7 @@ impl DefMap {
within_impl: bool,
) -> Option<Visibility> {
let mut vis = match visibility {
RawVisibility::Module(path) => {
RawVisibility::Module(path, explicity) => {
let (result, remaining) =
self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None);
if remaining.is_some() {
@ -95,7 +95,7 @@ impl DefMap {
}
let types = result.take_types()?;
match types {
ModuleDefId::ModuleId(m) => Visibility::Module(m),
ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicity),
// error: visibility needs to refer to module
_ => {
return None;
@ -108,11 +108,11 @@ impl DefMap {
// In block expressions, `self` normally refers to the containing non-block module, and
// `super` to its parent (etc.). However, visibilities must only refer to a module in the
// DefMap they're written in, so we restrict them when that happens.
if let Visibility::Module(m) = vis {
if let Visibility::Module(m, mv) = vis {
// ...unless we're resolving visibility for an associated item in an impl.
if self.block_id() != m.block && !within_impl {
cov_mark::hit!(adjust_vis_in_block_def_map);
vis = Visibility::Module(self.module_id(Self::ROOT));
vis = Visibility::Module(self.module_id(Self::ROOT), mv);
tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
}
}

View File

@ -1264,6 +1264,54 @@ struct A;
);
}
#[test]
fn nested_include() {
check(
r#"
//- minicore: include
//- /lib.rs
include!("out_dir/includes.rs");
//- /out_dir/includes.rs
pub mod company_name {
pub mod network {
pub mod v1 {
include!("company_name.network.v1.rs");
}
}
}
//- /out_dir/company_name.network.v1.rs
pub struct IpAddress {
pub ip_type: &'static str,
}
/// Nested message and enum types in `IpAddress`.
pub mod ip_address {
pub enum IpType {
IpV4(u32),
}
}
"#,
expect![[r#"
crate
company_name: t
crate::company_name
network: t
crate::company_name::network
v1: t
crate::company_name::network::v1
IpAddress: t
ip_address: t
crate::company_name::network::v1::ip_address
IpType: t
"#]],
);
}
#[test]
fn macro_use_imports_all_macro_types() {
let db = TestDB::with_files(

View File

@ -242,7 +242,7 @@ impl Resolver {
let within_impl =
self.scopes().find(|scope| matches!(scope, Scope::ImplDefScope(_))).is_some();
match visibility {
RawVisibility::Module(_) => {
RawVisibility::Module(_, _) => {
let (item_map, module) = self.item_scope();
item_map.resolve_visibility(db, module, visibility, within_impl)
}

View File

@ -8,7 +8,6 @@ use base_db::{
Upcast,
};
use hir_expand::{db::ExpandDatabase, InFile};
use rustc_hash::FxHashSet;
use syntax::{algo, ast, AstNode};
use triomphe::Arc;
@ -76,7 +75,7 @@ impl FileLoader for TestDB {
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
FileLoaderDelegate(self).resolve_path(path)
}
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> {
FileLoaderDelegate(self).relevant_crates(file_id)
}
}

View File

@ -20,14 +20,14 @@ use crate::{
pub enum RawVisibility {
/// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
/// equivalent to `pub(self)`.
Module(ModPath),
Module(ModPath, VisibilityExplicity),
/// `pub`.
Public,
}
impl RawVisibility {
pub(crate) const fn private() -> RawVisibility {
RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)))
RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicity::Implicit)
}
pub(crate) fn from_ast(
@ -41,18 +41,9 @@ impl RawVisibility {
db: &dyn DefDatabase,
node: Option<ast::Visibility>,
span_map: SpanMapRef<'_>,
) -> RawVisibility {
Self::from_ast_with_span_map_and_default(db, node, RawVisibility::private(), span_map)
}
pub(crate) fn from_ast_with_span_map_and_default(
db: &dyn DefDatabase,
node: Option<ast::Visibility>,
default: RawVisibility,
span_map: SpanMapRef<'_>,
) -> RawVisibility {
let node = match node {
None => return default,
None => return RawVisibility::private(),
Some(node) => node,
};
match node.kind() {
@ -62,19 +53,19 @@ impl RawVisibility {
None => return RawVisibility::private(),
Some(path) => path,
};
RawVisibility::Module(path)
RawVisibility::Module(path, VisibilityExplicity::Explicit)
}
ast::VisibilityKind::PubCrate => {
let path = ModPath::from_kind(PathKind::Crate);
RawVisibility::Module(path)
RawVisibility::Module(path, VisibilityExplicity::Explicit)
}
ast::VisibilityKind::PubSuper => {
let path = ModPath::from_kind(PathKind::Super(1));
RawVisibility::Module(path)
RawVisibility::Module(path, VisibilityExplicity::Explicit)
}
ast::VisibilityKind::PubSelf => {
let path = ModPath::from_kind(PathKind::Super(0));
RawVisibility::Module(path)
RawVisibility::Module(path, VisibilityExplicity::Explicit)
}
ast::VisibilityKind::Pub => RawVisibility::Public,
}
@ -94,7 +85,7 @@ impl RawVisibility {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Visibility {
/// Visibility is restricted to a certain module.
Module(ModuleId),
Module(ModuleId, VisibilityExplicity),
/// Visibility is unrestricted.
Public,
}
@ -102,7 +93,7 @@ pub enum Visibility {
impl Visibility {
pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
let to_module = match self {
Visibility::Module(m) => m,
Visibility::Module(m, _) => m,
Visibility::Public => return true,
};
// if they're not in the same crate, it can't be visible
@ -124,7 +115,7 @@ impl Visibility {
mut from_module: LocalModuleId,
) -> bool {
let mut to_module = match self {
Visibility::Module(m) => m,
Visibility::Module(m, _) => m,
Visibility::Public => return true,
};
@ -181,9 +172,9 @@ impl Visibility {
/// visible in unrelated modules).
pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
match (self, other) {
(Visibility::Module(_) | Visibility::Public, Visibility::Public)
| (Visibility::Public, Visibility::Module(_)) => Some(Visibility::Public),
(Visibility::Module(mod_a), Visibility::Module(mod_b)) => {
(Visibility::Module(_, _) | Visibility::Public, Visibility::Public)
| (Visibility::Public, Visibility::Module(_, _)) => Some(Visibility::Public),
(Visibility::Module(mod_a, vis_a), Visibility::Module(mod_b, vis_b)) => {
if mod_a.krate != mod_b.krate {
return None;
}
@ -199,12 +190,12 @@ impl Visibility {
if a_ancestors.any(|m| m == mod_b.local_id) {
// B is above A
return Some(Visibility::Module(mod_b));
return Some(Visibility::Module(mod_b, vis_b));
}
if b_ancestors.any(|m| m == mod_a.local_id) {
// A is above B
return Some(Visibility::Module(mod_a));
return Some(Visibility::Module(mod_a, vis_a));
}
None
@ -213,6 +204,19 @@ impl Visibility {
}
}
/// Whether the item was imported through `pub(crate) use` or just `use`.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum VisibilityExplicity {
Explicit,
Implicit,
}
impl VisibilityExplicity {
pub fn is_explicit(&self) -> bool {
matches!(self, Self::Explicit)
}
}
/// Resolve visibility of all specific fields of a struct or union variant.
pub(crate) fn field_visibilities_query(
db: &dyn DefDatabase,

View File

@ -1,6 +1,5 @@
//! Builtin derives.
use base_db::{CrateOrigin, LangCrateOrigin};
use itertools::izip;
use rustc_hash::FxHashSet;
use span::{MacroCallId, Span};
@ -10,6 +9,7 @@ use tracing::debug;
use crate::{
hygiene::span_with_def_site_ctxt,
name::{AsName, Name},
quote::dollar_crate,
span_map::SpanMapRef,
tt,
};
@ -38,7 +38,7 @@ macro_rules! register_builtin {
let span = db.lookup_intern_macro_call(id).call_site;
let span = span_with_def_site_ctxt(db, span, id);
expander(db, id, span, tt, token_map)
expander(span, tt, token_map)
}
fn find_by_name(name: &name::Name) -> Option<Self> {
@ -398,41 +398,13 @@ fn expand_simple_derive(
ExpandResult::ok(expanded)
}
fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId, span: Span) -> tt::TokenTree {
// FIXME: make hygiene works for builtin derive macro
// such that $crate can be used here.
let cg = db.crate_graph();
let krate = db.lookup_intern_macro_call(id).krate;
let tt = if matches!(cg[krate].origin, CrateOrigin::Lang(LangCrateOrigin::Core)) {
cov_mark::hit!(test_copy_expand_in_core);
quote! {span => crate }
} else {
quote! {span => core }
};
tt.token_trees[0].clone()
}
fn copy_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id, span);
fn copy_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::marker::Copy }, |_| quote! {span =>})
}
fn clone_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id, span);
fn clone_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::clone::Clone }, |adt| {
if matches!(adt.shape, AdtShape::Union) {
let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
@ -482,14 +454,8 @@ fn and_and(span: Span) -> tt::Subtree {
quote! {span => #and& }
}
fn default_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id, span);
fn default_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = &dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::default::Default }, |adt| {
let body = match &adt.shape {
AdtShape::Struct(fields) => {
@ -527,14 +493,8 @@ fn default_expand(
})
}
fn debug_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id, span);
fn debug_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = &dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::fmt::Debug }, |adt| {
let for_variant = |name: String, v: &VariantShape| match v {
VariantShape::Struct(fields) => {
@ -605,14 +565,8 @@ fn debug_expand(
})
}
fn hash_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id, span);
fn hash_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = &dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::hash::Hash }, |adt| {
if matches!(adt.shape, AdtShape::Union) {
// FIXME: Return expand error here
@ -658,25 +612,13 @@ fn hash_expand(
})
}
fn eq_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id, span);
fn eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>})
}
fn partial_eq_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id, span);
fn partial_eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialEq }, |adt| {
if matches!(adt.shape, AdtShape::Union) {
// FIXME: Return expand error here
@ -747,17 +689,11 @@ fn self_and_other_patterns(
(self_patterns, other_patterns)
}
fn ord_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id, span);
fn ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = &dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Ord }, |adt| {
fn compare(
krate: &tt::TokenTree,
krate: &tt::Ident,
left: tt::Subtree,
right: tt::Subtree,
rest: tt::Subtree,
@ -811,17 +747,11 @@ fn ord_expand(
})
}
fn partial_ord_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id, span);
fn partial_ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = &dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialOrd }, |adt| {
fn compare(
krate: &tt::TokenTree,
krate: &tt::Ident,
left: tt::Subtree,
right: tt::Subtree,
rest: tt::Subtree,

View File

@ -6,18 +6,16 @@ use either::Either;
use itertools::Itertools;
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
use span::{Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
use syntax::{
ast::{self, AstToken},
SmolStr,
};
use syntax::ast::{self, AstToken};
use crate::{
db::ExpandDatabase,
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
name::{self, known},
quote,
quote::dollar_crate,
tt::{self, DelimSpan},
ExpandError, ExpandResult, HirFileIdExt, MacroCallId,
ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroFileIdExt,
};
macro_rules! register_builtin {
@ -205,7 +203,7 @@ fn assert_expand(
) -> ExpandResult<tt::Subtree> {
let call_site_span = span_with_call_site_ctxt(db, span, id);
let args = parse_exprs_with_sep(tt, ',', call_site_span);
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let dollar_crate = dollar_crate(span);
let expanded = match &*args {
[cond, panic_args @ ..] => {
let comma = tt::Subtree {
@ -300,7 +298,7 @@ fn asm_expand(
[tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
| [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] =>
{
let dollar_krate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let dollar_krate = dollar_crate(span);
literals.push(quote!(span=>#dollar_krate::format_args!(#lit);));
}
_ => break,
@ -345,7 +343,7 @@ fn panic_expand(
tt: &tt::Subtree,
span: Span,
) -> ExpandResult<tt::Subtree> {
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let dollar_crate = dollar_crate(span);
let call_site_span = span_with_call_site_ctxt(db, span, id);
let mac =
@ -371,7 +369,7 @@ fn unreachable_expand(
tt: &tt::Subtree,
span: Span,
) -> ExpandResult<tt::Subtree> {
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let dollar_crate = dollar_crate(span);
let call_site_span = span_with_call_site_ctxt(db, span, id);
let mac = if use_panic_2021(db, call_site_span) {
@ -611,7 +609,7 @@ fn relative_file(
path_str: &str,
allow_recursion: bool,
) -> Result<FileId, ExpandError> {
let call_site = call_id.as_file().original_file(db);
let call_site = call_id.as_macro_file().parent(db).original_file_respecting_includes(db);
let path = AnchoredPath { anchor: call_site, path: path_str };
let res = db
.resolve_path(path)
@ -763,10 +761,10 @@ fn option_env_expand(
return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
}
};
// FIXME: Use `DOLLAR_CRATE` when that works in eager macros.
let dollar_crate = dollar_crate(span);
let expanded = match get_env_inner(db, arg_id, &key) {
None => quote! {span => ::core::option::Option::None::<&str> },
Some(s) => quote! {span => ::core::option::Option::Some(#s) },
None => quote! {span => #dollar_crate::option::Option::None::<&str> },
Some(s) => quote! {span => #dollar_crate::option::Option::Some(#s) },
};
ExpandResult::ok(expanded)

View File

@ -318,6 +318,7 @@ pub trait MacroFileIdExt {
fn expansion_level(self, db: &dyn ExpandDatabase) -> u32;
/// If this is a macro call, returns the syntax node of the call.
fn call_node(self, db: &dyn ExpandDatabase) -> InFile<SyntaxNode>;
fn parent(self, db: &dyn ExpandDatabase) -> HirFileId;
fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo;
@ -353,6 +354,9 @@ impl MacroFileIdExt for MacroFileId {
};
}
}
fn parent(self, db: &dyn ExpandDatabase) -> HirFileId {
self.macro_call_id.lookup(db).kind.file_id()
}
/// Return expansion information if it is a macro-expansion file
fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo {

View File

@ -4,6 +4,10 @@ use span::Span;
use crate::name::Name;
pub(crate) fn dollar_crate(span: Span) -> tt::Ident<Span> {
tt::Ident { text: syntax::SmolStr::new_inline("$crate"), span }
}
// A helper macro quote macro
// FIXME:
// 1. Not all puncts are handled

View File

@ -34,7 +34,9 @@ nohash-hasher.workspace = true
typed-arena = "2.0.1"
indexmap.workspace = true
rustc-dependencies.workspace = true
ra-ap-rustc_abi.workspace = true
ra-ap-rustc_index.workspace = true
# local deps
stdx.workspace = true
@ -58,7 +60,7 @@ test-utils.workspace = true
test-fixture.workspace = true
[features]
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
in-rust-tree = []
[lints]
workspace = true

View File

@ -167,7 +167,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
}
});
})
.map(|block_id| self.db.trait_impls_in_block(block_id));
.filter_map(|block_id| self.db.trait_impls_in_block(block_id));
let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
let mut result = vec![];
@ -183,7 +183,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
def_blocks
.into_iter()
.flatten()
.for_each(|it| f(&self.db.trait_impls_in_block(it)));
.filter_map(|it| self.db.trait_impls_in_block(it))
.for_each(|it| f(&it));
}
fps => {
let mut f =
@ -198,7 +199,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
def_blocks
.into_iter()
.flatten()
.for_each(|it| f(&self.db.trait_impls_in_block(it)));
.filter_map(|it| self.db.trait_impls_in_block(it))
.for_each(|it| f(&it));
}
}

View File

@ -34,6 +34,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::infer::infer_query)]
fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
// region:mir
#[salsa::invoke(crate::mir::mir_body_query)]
#[salsa::cycle(crate::mir::mir_body_recover)]
fn mir_body(&self, def: DefWithBodyId) -> Result<Arc<MirBody>, MirLowerError>;
@ -61,20 +63,6 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::mir::borrowck_query)]
fn borrowck(&self, def: DefWithBodyId) -> Result<Arc<[BorrowckResult]>, MirLowerError>;
#[salsa::invoke(crate::lower::ty_query)]
#[salsa::cycle(crate::lower::ty_recover)]
fn ty(&self, def: TyDefId) -> Binders<Ty>;
#[salsa::invoke(crate::lower::value_ty_query)]
fn value_ty(&self, def: ValueTyDefId) -> Binders<Ty>;
#[salsa::invoke(crate::lower::impl_self_ty_query)]
#[salsa::cycle(crate::lower::impl_self_ty_recover)]
fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
#[salsa::invoke(crate::lower::const_param_ty_query)]
fn const_param_ty(&self, def: ConstParamId) -> Ty;
#[salsa::invoke(crate::consteval::const_eval_query)]
#[salsa::cycle(crate::consteval::const_eval_recover)]
fn const_eval(
@ -92,6 +80,22 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::cycle(crate::consteval::const_eval_discriminant_recover)]
fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>;
// endregion:mir
#[salsa::invoke(crate::lower::ty_query)]
#[salsa::cycle(crate::lower::ty_recover)]
fn ty(&self, def: TyDefId) -> Binders<Ty>;
#[salsa::invoke(crate::lower::value_ty_query)]
fn value_ty(&self, def: ValueTyDefId) -> Binders<Ty>;
#[salsa::invoke(crate::lower::impl_self_ty_query)]
#[salsa::cycle(crate::lower::impl_self_ty_recover)]
fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
#[salsa::invoke(crate::lower::const_param_ty_query)]
fn const_param_ty(&self, def: ConstParamId) -> Ty;
#[salsa::invoke(crate::lower::impl_trait_query)]
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
@ -158,7 +162,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
#[salsa::invoke(InherentImpls::inherent_impls_in_block_query)]
fn inherent_impls_in_block(&self, block: BlockId) -> Arc<InherentImpls>;
fn inherent_impls_in_block(&self, block: BlockId) -> Option<Arc<InherentImpls>>;
/// Collects all crates in the dependency graph that have impls for the
/// given fingerprint. This is only used for primitive types and types
@ -175,7 +179,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
#[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
fn trait_impls_in_block(&self, block: BlockId) -> Arc<TraitImpls>;
fn trait_impls_in_block(&self, block: BlockId) -> Option<Arc<TraitImpls>>;
#[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<[Arc<TraitImpls>]>;

View File

@ -1629,7 +1629,7 @@ pub fn write_visibility(
) -> Result<(), HirDisplayError> {
match vis {
Visibility::Public => write!(f, "pub "),
Visibility::Module(vis_id) => {
Visibility::Module(vis_id, _) => {
let def_map = module_id.def_map(f.db.upcast());
let root_module_id = def_map.module_id(DefMap::ROOT);
if vis_id == module_id {

View File

@ -12,10 +12,9 @@ use hir_def::{
LocalEnumVariantId, LocalFieldId, StructId,
};
use la_arena::{Idx, RawIdx};
use rustc_dependencies::{
abi::AddressSpace,
index::{IndexSlice, IndexVec},
};
use rustc_abi::AddressSpace;
use rustc_index::{IndexSlice, IndexVec};
use stdx::never;
use triomphe::Arc;
@ -35,7 +34,7 @@ mod target;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
impl rustc_dependencies::index::Idx for RustcEnumVariantIdx {
impl rustc_index::Idx for RustcEnumVariantIdx {
fn new(idx: usize) -> Self {
RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32)))
}
@ -54,7 +53,7 @@ impl RustcFieldIdx {
}
}
impl rustc_dependencies::index::Idx for RustcFieldIdx {
impl rustc_index::Idx for RustcFieldIdx {
fn new(idx: usize) -> Self {
RustcFieldIdx(Idx::from_raw(RawIdx::from(idx as u32)))
}

View File

@ -9,7 +9,7 @@ use hir_def::{
AdtId, EnumVariantId, LocalEnumVariantId, VariantId,
};
use la_arena::RawIdx;
use rustc_dependencies::index::IndexVec;
use rustc_index::IndexVec;
use smallvec::SmallVec;
use triomphe::Arc;

View File

@ -118,7 +118,7 @@ fn check_fail(ra_fixture: &str, e: LayoutError) {
macro_rules! size_and_align {
(minicore: $($x:tt),*;$($t:tt)*) => {
{
#[allow(dead_code)]
#![allow(dead_code)]
$($t)*
check_size_and_align(
stringify!($($t)*),
@ -130,7 +130,7 @@ macro_rules! size_and_align {
};
($($t:tt)*) => {
{
#[allow(dead_code)]
#![allow(dead_code)]
$($t)*
check_size_and_align(
stringify!($($t)*),

View File

@ -3,10 +3,17 @@
#![warn(rust_2018_idioms, unused_lifetimes)]
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#[allow(unused)]
macro_rules! eprintln {
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
}
#[cfg(feature = "in-rust-tree")]
extern crate rustc_index;
#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_index as rustc_index;
#[cfg(feature = "in-rust-tree")]
extern crate rustc_abi;
#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_abi as rustc_abi;
mod builder;
mod chalk_db;

View File

@ -1601,7 +1601,7 @@ fn implicitly_sized_clauses<'a>(
pub(crate) fn generic_defaults_query(
db: &dyn HirDatabase,
def: GenericDefId,
) -> Arc<[Binders<chalk_ir::GenericArg<Interner>>]> {
) -> Arc<[Binders<crate::GenericArg>]> {
let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, def.into())
.with_type_param_mode(ParamLoweringMode::Variable);

View File

@ -8,10 +8,9 @@ use base_db::{CrateId, Edition};
use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause};
use hir_def::{
data::{adt::StructFlags, ImplData},
item_scope::ItemScope,
nameres::DefMap,
AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
ModuleDefId, ModuleId, TraitId,
ModuleId, TraitId,
};
use hir_expand::name::Name;
use rustc_hash::{FxHashMap, FxHashSet};
@ -132,34 +131,40 @@ pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)),
];
type TraitFpMap = FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Box<[ImplId]>>>;
type TraitFpMapCollector = FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>;
/// Trait impls defined or available in some crate.
#[derive(Debug, Eq, PartialEq)]
pub struct TraitImpls {
// If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
map: TraitFpMap,
}
impl TraitImpls {
pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
let _p = profile::span("trait_impls_in_crate_query").detail(|| format!("{krate:?}"));
let mut impls = Self { map: FxHashMap::default() };
let mut impls = FxHashMap::default();
let crate_def_map = db.crate_def_map(krate);
impls.collect_def_map(db, &crate_def_map);
impls.shrink_to_fit();
Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate));
Arc::new(impls)
Arc::new(Self::finish(impls))
}
pub(crate) fn trait_impls_in_block_query(db: &dyn HirDatabase, block: BlockId) -> Arc<Self> {
pub(crate) fn trait_impls_in_block_query(
db: &dyn HirDatabase,
block: BlockId,
) -> Option<Arc<Self>> {
let _p = profile::span("trait_impls_in_block_query");
let mut impls = Self { map: FxHashMap::default() };
let mut impls = FxHashMap::default();
let block_def_map = db.block_def_map(block);
impls.collect_def_map(db, &block_def_map);
impls.shrink_to_fit();
Self::collect_def_map(db, &mut impls, &db.block_def_map(block));
Arc::new(impls)
if impls.is_empty() {
None
} else {
Some(Arc::new(Self::finish(impls)))
}
}
pub(crate) fn trait_impls_in_deps_query(
@ -174,15 +179,16 @@ impl TraitImpls {
)
}
fn shrink_to_fit(&mut self) {
self.map.shrink_to_fit();
self.map.values_mut().for_each(|map| {
map.shrink_to_fit();
map.values_mut().for_each(Vec::shrink_to_fit);
});
fn finish(map: TraitFpMapCollector) -> TraitImpls {
TraitImpls {
map: map
.into_iter()
.map(|(k, v)| (k, v.into_iter().map(|(k, v)| (k, v.into_boxed_slice())).collect()))
.collect(),
}
}
fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
fn collect_def_map(db: &dyn HirDatabase, map: &mut TraitFpMapCollector, def_map: &DefMap) {
for (_module_id, module_data) in def_map.modules() {
for impl_id in module_data.scope.impls() {
// Reservation impls should be ignored during trait resolution, so we never need
@ -200,20 +206,15 @@ impl TraitImpls {
};
let self_ty = db.impl_self_ty(impl_id);
let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
self.map
.entry(target_trait)
.or_default()
.entry(self_ty_fp)
.or_default()
.push(impl_id);
map.entry(target_trait).or_default().entry(self_ty_fp).or_default().push(impl_id);
}
// To better support custom derives, collect impls in all unnamed const items.
// const _: () = { ... };
for konst in collect_unnamed_consts(db, &module_data.scope) {
for konst in module_data.scope.unnamed_consts(db.upcast()) {
let body = db.body(konst.into());
for (_, block_def_map) in body.blocks(db.upcast()) {
self.collect_def_map(db, &block_def_map);
Self::collect_def_map(db, map, &block_def_map);
}
}
}
@ -281,7 +282,10 @@ impl InherentImpls {
Arc::new(impls)
}
pub(crate) fn inherent_impls_in_block_query(db: &dyn HirDatabase, block: BlockId) -> Arc<Self> {
pub(crate) fn inherent_impls_in_block_query(
db: &dyn HirDatabase,
block: BlockId,
) -> Option<Arc<Self>> {
let _p = profile::span("inherent_impls_in_block_query");
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
@ -289,7 +293,11 @@ impl InherentImpls {
impls.collect_def_map(db, &block_def_map);
impls.shrink_to_fit();
Arc::new(impls)
if impls.map.is_empty() && impls.invalid_impls.is_empty() {
None
} else {
Some(Arc::new(impls))
}
}
fn shrink_to_fit(&mut self) {
@ -321,7 +329,7 @@ impl InherentImpls {
// To better support custom derives, collect impls in all unnamed const items.
// const _: () = { ... };
for konst in collect_unnamed_consts(db, &module_data.scope) {
for konst in module_data.scope.unnamed_consts(db.upcast()) {
let body = db.body(konst.into());
for (_, block_def_map) in body.blocks(db.upcast()) {
self.collect_def_map(db, &block_def_map);
@ -367,34 +375,6 @@ pub(crate) fn incoherent_inherent_impl_crates(
res
}
fn collect_unnamed_consts<'a>(
db: &'a dyn HirDatabase,
scope: &'a ItemScope,
) -> impl Iterator<Item = ConstId> + 'a {
let unnamed_consts = scope.unnamed_consts();
// FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those.
// Should be removed once synstructure stops doing that.
let synstructure_hack_consts = scope.values().filter_map(|(item, _)| match item {
ModuleDefId::ConstId(id) => {
let loc = id.lookup(db.upcast());
let item_tree = loc.id.item_tree(db.upcast());
if item_tree[loc.id.value]
.name
.as_ref()
.map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_"))
{
Some(id)
} else {
None
}
}
_ => None,
});
unnamed_consts.chain(synstructure_hack_consts)
}
pub fn def_crates(
db: &dyn HirDatabase,
ty: &Ty,
@ -737,7 +717,7 @@ fn lookup_impl_assoc_item_for_trait_ref(
let impls = db.trait_impls_in_deps(env.krate);
let self_impls = match self_ty.kind(Interner) {
TyKind::Adt(id, _) => {
id.0.module(db.upcast()).containing_block().map(|it| db.trait_impls_in_block(it))
id.0.module(db.upcast()).containing_block().and_then(|it| db.trait_impls_in_block(it))
}
_ => None,
};
@ -1254,17 +1234,18 @@ fn iterate_inherent_methods(
};
while let Some(block_id) = block {
let impls = db.inherent_impls_in_block(block_id);
impls_for_self_ty(
&impls,
self_ty,
table,
name,
receiver_ty,
receiver_adjustments.clone(),
module,
callback,
)?;
if let Some(impls) = db.inherent_impls_in_block(block_id) {
impls_for_self_ty(
&impls,
self_ty,
table,
name,
receiver_ty,
receiver_adjustments.clone(),
module,
callback,
)?;
}
block = db.block_def_map(block_id).parent().and_then(|module| module.containing_block());
}

View File

@ -9,7 +9,6 @@ use base_db::{
use hir_def::{db::DefDatabase, ModuleId};
use hir_expand::db::ExpandDatabase;
use nohash_hasher::IntMap;
use rustc_hash::FxHashSet;
use syntax::TextRange;
use test_utils::extract_annotations;
use triomphe::Arc;
@ -81,7 +80,7 @@ impl FileLoader for TestDB {
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
FileLoaderDelegate(self).resolve_path(path)
}
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> {
FileLoaderDelegate(self).relevant_crates(file_id)
}
}

View File

@ -987,15 +987,12 @@ fn infer_builtin_macros_env() {
fn infer_builtin_macros_option_env() {
check_types(
r#"
//- minicore: option
//- /main.rs env:foo=bar
#[rustc_builtin_macro]
macro_rules! option_env {() => {}}
fn main() {
let x = option_env!("foo");
//^ Option<&str>
}
//- minicore: env
//- /main.rs env:foo=bar
fn main() {
let x = option_env!("foo");
//^ Option<&str>
}
"#,
);
}
@ -1014,6 +1011,21 @@ fn test() {
);
}
#[test]
fn infer_builtin_derive_resolves_with_core_module() {
check_types(
r#"
//- minicore: derive, clone
mod core {}
#[derive(Clone)]
struct S;
fn test() {
S.clone();
} //^^^^^^^^^ S
"#,
);
}
#[test]
fn infer_derive_clone_with_params() {
check_types(

View File

@ -35,7 +35,7 @@ macro_rules! impl_has_attrs {
impl HasAttrs for $def {
fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
let def = AttrDefId::$def_id(self.into());
db.attrs_with_owner(def)
AttrsWithOwner::attrs_with_owner(db.upcast(), def)
}
fn attr_id(self) -> AttrDefId {
AttrDefId::$def_id(self.into())

View File

@ -15,8 +15,8 @@ pub use hir_def::db::{
InternExternBlockQuery, InternExternCrateQuery, InternFunctionQuery, InternImplQuery,
InternInTypeConstQuery, InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery,
InternStaticQuery, InternStructQuery, InternTraitAliasQuery, InternTraitQuery,
InternTypeAliasQuery, InternUnionQuery, InternUseQuery, LangAttrQuery, LangItemQuery,
Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery,
InternTypeAliasQuery, InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery,
MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery,
StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataQuery,
TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataQuery,
UnionDataWithDiagnosticsQuery, VariantsAttrsQuery, VariantsAttrsSourceMapQuery,

View File

@ -754,7 +754,7 @@ impl Module {
scope
.declarations()
.map(ModuleDef::from)
.chain(scope.unnamed_consts().map(|id| ModuleDef::Const(Const::from(id))))
.chain(scope.unnamed_consts(db.upcast()).map(|id| ModuleDef::Const(Const::from(id))))
.collect()
}

View File

@ -165,6 +165,7 @@ impl<'a> SymbolCollector<'a> {
// Record renamed imports.
// FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily
// for now.
// FIXME: This parses!
for id in scope.imports() {
let source = id.import.child_source(self.db.upcast());
let Some(use_tree_src) = source.value.get(id.idx) else { continue };
@ -195,7 +196,7 @@ impl<'a> SymbolCollector<'a> {
});
}
for const_id in scope.unnamed_consts() {
for const_id in scope.unnamed_consts(self.db.upcast()) {
self.collect_from_body(const_id);
}

View File

@ -1551,4 +1551,39 @@ use foo::Foo$0;
",
);
}
#[test]
fn considers_pub_crate() {
check_assist(
auto_import,
r#"
mod foo {
pub struct Foo;
}
pub(crate) use self::foo::*;
mod bar {
fn main() {
Foo$0;
}
}
"#,
r#"
mod foo {
pub struct Foo;
}
pub(crate) use self::foo::*;
mod bar {
use crate::Foo;
fn main() {
Foo;
}
}
"#,
);
}
}

View File

@ -25,7 +25,7 @@ use syntax::{
edit::{AstNodeEdit, IndentLevel},
AstNode, HasGenericParams,
},
match_ast, ted, SyntaxElement,
match_ast, ted, AstToken, SyntaxElement,
SyntaxKind::{self, COMMENT},
SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
};
@ -1733,8 +1733,23 @@ fn make_body(
ast::Expr::BlockExpr(block) => {
// If the extracted expression is itself a block, there is no need to wrap it inside another block.
let block = block.dedent(old_indent);
// Recreate the block for formatting consistency with other extracted functions.
make::block_expr(block.statements(), block.tail_expr())
let elements = block.stmt_list().map_or_else(
|| Either::Left(iter::empty()),
|stmt_list| {
let elements = stmt_list.syntax().children_with_tokens().filter_map(
|node_or_token| match &node_or_token {
syntax::NodeOrToken::Node(node) => {
ast::Stmt::cast(node.clone()).map(|_| node_or_token)
}
syntax::NodeOrToken::Token(token) => {
ast::Comment::cast(token.clone()).map(|_| node_or_token)
}
},
);
Either::Right(elements)
},
);
make::hacky_block_expr(elements, block.tail_expr())
}
_ => {
let expr = expr.dedent(old_indent).indent(IndentLevel(1));
@ -5961,6 +5976,37 @@ fn $0fun_name() -> ControlFlow<()> {
);
}
#[test]
fn comments_in_block_expr() {
check_assist(
extract_function,
r#"
fn f() {
let c = $0{
// comment 1
let a = 2 + 3;
// comment 2
let b = 5;
a + b
}$0;
}
"#,
r#"
fn f() {
let c = fun_name();
}
fn $0fun_name() -> i32 {
// comment 1
let a = 2 + 3;
// comment 2
let b = 5;
a + b
}
"#,
);
}
#[test]
fn in_left_curly_is_not_applicable() {
cov_mark::check!(extract_function_in_braces_is_not_applicable);

View File

@ -50,6 +50,10 @@ pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
ty.original().display_source_code(ctx.db(), constant_module.into(), false).ok()?;
let target = statement.syntax().parent()?.text_range();
let path = constant_token.syntax().ancestors().find_map(ast::Path::cast)?;
if path.parent_path().is_some() {
cov_mark::hit!(not_last_path_segment);
return None;
}
let name_refs = path.segments().map(|s| s.name_ref());
let mut outer_exists = false;
@ -250,6 +254,18 @@ fn bar() -> i32 {
}
fn bar() -> i32 {
foo::goo::A_CONSTANT
}"#,
);
}
#[test]
fn test_wont_apply_when_not_last_path_segment() {
cov_mark::check!(not_last_path_segment);
check_assist_not_applicable(
generate_constant,
r#"mod foo {}
fn bar() -> i32 {
foo::A_CON$0STANT::invalid_segment
}"#,
);
}

View File

@ -107,31 +107,48 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
|edit| {
// Create the function
let method_source = match ctx.sema.source(method) {
Some(source) => source.value,
Some(source) => {
let v = source.value.clone_for_update();
let source_scope = ctx.sema.scope(v.syntax());
let target_scope = ctx.sema.scope(strukt.syntax());
if let (Some(s), Some(t)) = (source_scope, target_scope) {
PathTransform::generic_transformation(&t, &s).apply(v.syntax());
}
v
}
None => return,
};
let vis = method_source.visibility();
let fn_name = make::name(&name);
let params =
method_source.param_list().unwrap_or_else(|| make::param_list(None, []));
let type_params = method_source.generic_param_list();
let arg_list = match method_source.param_list() {
Some(list) => convert_param_list_to_arg_list(list),
None => make::arg_list([]),
};
let tail_expr = make::expr_method_call(field, make::name_ref(&name), arg_list);
let ret_type = method_source.ret_type();
let is_async = method_source.async_token().is_some();
let is_const = method_source.const_token().is_some();
let is_unsafe = method_source.unsafe_token().is_some();
let fn_name = make::name(&name);
let type_params = method_source.generic_param_list();
let where_clause = method_source.where_clause();
let params =
method_source.param_list().unwrap_or_else(|| make::param_list(None, []));
// compute the `body`
let arg_list = method_source
.param_list()
.map(|list| convert_param_list_to_arg_list(list))
.unwrap_or_else(|| make::arg_list([]));
let tail_expr = make::expr_method_call(field, make::name_ref(&name), arg_list);
let tail_expr_finished =
if is_async { make::expr_await(tail_expr) } else { tail_expr };
let body = make::block_expr([], Some(tail_expr_finished));
let ret_type = method_source.ret_type();
let f = make::fn_(
vis,
fn_name,
type_params,
method_source.where_clause(),
where_clause,
params,
body,
ret_type,
@ -184,12 +201,6 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
let assoc_items = impl_def.get_or_create_assoc_item_list();
assoc_items.add_item(f.clone().into());
if let Some((target, source)) =
ctx.sema.scope(strukt.syntax()).zip(ctx.sema.scope(method_source.syntax()))
{
PathTransform::generic_transformation(&target, &source).apply(f.syntax());
}
if let Some(cap) = ctx.config.snippet_cap {
edit.add_tabstop_before(cap, f)
}

View File

@ -0,0 +1,246 @@
use ide_db::syntax_helpers::node_ext::is_pattern_cond;
use syntax::{
ast::{self, AstNode, BinaryOp},
T,
};
use crate::{
assist_context::{AssistContext, Assists},
AssistId, AssistKind,
};
// Assist: merge_nested_if
//
// This transforms if expressions of the form `if x { if y {A} }` into `if x && y {A}`
// This assist can only be applied with the cursor on `if`.
//
// ```
// fn main() {
// i$0f x == 3 { if y == 4 { 1 } }
// }
// ```
// ->
// ```
// fn main() {
// if x == 3 && y == 4 { 1 }
// }
// ```
pub(crate) fn merge_nested_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let if_keyword = ctx.find_token_syntax_at_offset(T![if])?;
let expr = ast::IfExpr::cast(if_keyword.parent()?)?;
let if_range = if_keyword.text_range();
let cursor_in_range = if_range.contains_range(ctx.selection_trimmed());
if !cursor_in_range {
return None;
}
//should not apply to if with else branch.
if expr.else_branch().is_some() {
return None;
}
let cond = expr.condition()?;
//should not apply for if-let
if is_pattern_cond(cond.clone()) {
return None;
}
let cond_range = cond.syntax().text_range();
//check if the then branch is a nested if
let then_branch = expr.then_branch()?;
let stmt = then_branch.stmt_list()?;
if stmt.statements().count() != 0 {
return None;
}
let nested_if_to_merge = then_branch.tail_expr().and_then(|e| match e {
ast::Expr::IfExpr(e) => Some(e),
_ => None,
})?;
// should not apply to nested if with else branch.
if nested_if_to_merge.else_branch().is_some() {
return None;
}
let nested_if_cond = nested_if_to_merge.condition()?;
if is_pattern_cond(nested_if_cond.clone()) {
return None;
}
let nested_if_then_branch = nested_if_to_merge.then_branch()?;
let then_branch_range = then_branch.syntax().text_range();
acc.add(
AssistId("merge_nested_if", AssistKind::RefactorRewrite),
"Merge nested if",
if_range,
|edit| {
let cond_text = if has_logic_op_or(&cond) {
format!("({})", cond.syntax().text())
} else {
cond.syntax().text().to_string()
};
let nested_if_cond_text = if has_logic_op_or(&nested_if_cond) {
format!("({})", nested_if_cond.syntax().text())
} else {
nested_if_cond.syntax().text().to_string()
};
let replace_cond = format!("{} && {}", cond_text, nested_if_cond_text);
edit.replace(cond_range, replace_cond);
edit.replace(then_branch_range, nested_if_then_branch.syntax().text());
},
)
}
/// Returns whether the given if condition has logical operators.
fn has_logic_op_or(expr: &ast::Expr) -> bool {
match expr {
ast::Expr::BinExpr(bin_expr) => {
if let Some(kind) = bin_expr.op_kind() {
matches!(kind, BinaryOp::LogicOp(ast::LogicOp::Or))
} else {
false
}
}
_ => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::{check_assist, check_assist_not_applicable};
#[test]
fn merge_nested_if_test1() {
check_assist(
merge_nested_if,
"fn f() { i$0f x == 3 { if y == 4 { 1 } } }",
"fn f() { if x == 3 && y == 4 { 1 } }",
)
}
#[test]
fn merge_nested_if_test2() {
check_assist(
merge_nested_if,
"fn f() { i$0f x == 3 || y == 1 { if z == 4 { 1 } } }",
"fn f() { if (x == 3 || y == 1) && z == 4 { 1 } }",
)
}
#[test]
fn merge_nested_if_test3() {
check_assist(
merge_nested_if,
"fn f() { i$0f x == 3 && y == 1 { if z == 4 { 1 } } }",
"fn f() { if x == 3 && y == 1 && z == 4 { 1 } }",
)
}
#[test]
fn merge_nested_if_test4() {
check_assist(
merge_nested_if,
"fn f() { i$0f x == 3 && y == 1 { if z == 4 && q == 3 { 1 } } }",
"fn f() { if x == 3 && y == 1 && z == 4 && q == 3 { 1 } }",
)
}
#[test]
fn merge_nested_if_test5() {
check_assist(
merge_nested_if,
"fn f() { i$0f x == 3 && y == 1 { if z == 4 || q == 3 { 1 } } }",
"fn f() { if x == 3 && y == 1 && (z == 4 || q == 3) { 1 } }",
)
}
#[test]
fn merge_nested_if_test6() {
check_assist(
merge_nested_if,
"fn f() { i$0f x == 3 || y == 1 { if z == 4 || q == 3 { 1 } } }",
"fn f() { if (x == 3 || y == 1) && (z == 4 || q == 3) { 1 } }",
)
}
#[test]
fn merge_nested_if_test7() {
check_assist(
merge_nested_if,
"fn f() { i$0f x == 3 || y == 1 { if z == 4 && q == 3 { 1 } } }",
"fn f() { if (x == 3 || y == 1) && z == 4 && q == 3 { 1 } }",
)
}
#[test]
fn merge_nested_if_do_not_apply_to_if_with_else_branch() {
check_assist_not_applicable(
merge_nested_if,
"fn f() { i$0f x == 3 { if y == 4 { 1 } } else { 2 } }",
)
}
#[test]
fn merge_nested_if_do_not_apply_to_nested_if_with_else_branch() {
check_assist_not_applicable(
merge_nested_if,
"fn f() { i$0f x == 3 { if y == 4 { 1 } else { 2 } } }",
)
}
#[test]
fn merge_nested_if_do_not_apply_to_if_let() {
check_assist_not_applicable(
merge_nested_if,
"fn f() { i$0f let Some(x) = y { if x == 4 { 1 } } }",
)
}
#[test]
fn merge_nested_if_do_not_apply_to_nested_if_let() {
check_assist_not_applicable(
merge_nested_if,
"fn f() { i$0f y == 0 { if let Some(x) = y { 1 } } }",
)
}
#[test]
fn merge_nested_if_do_not_apply_to_if_with_else_branch_and_nested_if() {
check_assist_not_applicable(
merge_nested_if,
"fn f() { i$0f x == 3 { if y == 4 { 1 } } else { if z == 5 { 2 } } }",
)
}
#[test]
fn merge_nested_if_do_not_apply_with_cursor_not_on_if() {
check_assist_not_applicable(merge_nested_if, "fn f() { if $0x==0 { if y == 3 { 1 } } }")
}
#[test]
fn merge_nested_if_do_not_apply_with_mulpiple_if() {
check_assist_not_applicable(
merge_nested_if,
"fn f() { i$0f x == 0 { if y == 3 { 1 } else if y == 4 { 2 } } }",
)
}
#[test]
fn merge_nested_if_do_not_apply_with_not_only_has_nested_if() {
check_assist_not_applicable(
merge_nested_if,
"fn f() { i$0f x == 0 { if y == 3 { foo(); } foo(); } }",
)
}
#[test]
fn merge_nested_if_do_not_apply_with_multiply_nested_if() {
check_assist_not_applicable(
merge_nested_if,
"fn f() { i$0f x == 0 { if y == 3 { foo(); } if z == 3 { 2 } } }",
)
}
}

View File

@ -217,6 +217,7 @@ mod handlers {
mod unqualify_method_call;
mod wrap_return_type_in_result;
mod into_to_qualified_from;
mod merge_nested_if;
pub(crate) fn all() -> &'static [Handler] {
&[
@ -291,6 +292,7 @@ mod handlers {
invert_if::invert_if,
merge_imports::merge_imports,
merge_match_arms::merge_match_arms,
merge_nested_if::merge_nested_if,
move_bounds::move_bounds_to_where_clause,
move_const_to_impl::move_const_to_impl,
move_guard::move_arm_cond_to_match_guard,

View File

@ -2051,6 +2051,23 @@ fn handle(action: Action) {
)
}
#[test]
fn doctest_merge_nested_if() {
check_doc_test(
"merge_nested_if",
r#####"
fn main() {
i$0f x == 3 { if y == 4 { 1 } }
}
"#####,
r#####"
fn main() {
if x == 3 && y == 4 { 1 }
}
"#####,
)
}
#[test]
fn doctest_move_arm_cond_to_match_guard() {
check_doc_test(

View File

@ -529,6 +529,11 @@ impl CompletionContext<'_> {
}
}
/// Whether the given trait has `#[doc(notable_trait)]`
pub(crate) fn is_doc_notable_trait(&self, trait_: hir::Trait) -> bool {
trait_.attrs(self.db).has_doc_notable_trait()
}
/// Returns the traits in scope, with the [`Drop`] trait removed.
pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
let mut traits_in_scope = self.scope.visible_traits();

View File

@ -152,6 +152,8 @@ pub struct CompletionRelevance {
pub is_local: bool,
/// This is set when trait items are completed in an impl of that trait.
pub is_item_from_trait: bool,
/// This is set for when trait items are from traits with `#[doc(notable_trait)]`
pub is_item_from_notable_trait: bool,
/// This is set when an import is suggested whose name is already imported.
pub is_name_already_imported: bool,
/// This is set for completions that will insert a `use` item.
@ -228,6 +230,7 @@ impl CompletionRelevance {
is_private_editable,
postfix_match,
is_definite,
is_item_from_notable_trait,
} = self;
// lower rank private things
@ -266,6 +269,9 @@ impl CompletionRelevance {
if is_item_from_trait {
score += 1;
}
if is_item_from_notable_trait {
score += 1;
}
if is_definite {
score += 10;
}

View File

@ -1170,6 +1170,7 @@ fn main() { let _: m::Spam = S$0 }
),
is_local: false,
is_item_from_trait: false,
is_item_from_notable_trait: false,
is_name_already_imported: false,
requires_import: false,
is_op_method: false,
@ -1196,6 +1197,7 @@ fn main() { let _: m::Spam = S$0 }
),
is_local: false,
is_item_from_trait: false,
is_item_from_notable_trait: false,
is_name_already_imported: false,
requires_import: false,
is_op_method: false,
@ -1274,6 +1276,7 @@ fn foo() { A { the$0 } }
),
is_local: false,
is_item_from_trait: false,
is_item_from_notable_trait: false,
is_name_already_imported: false,
requires_import: false,
is_op_method: false,
@ -2089,6 +2092,7 @@ fn foo() {
),
is_local: false,
is_item_from_trait: false,
is_item_from_notable_trait: false,
is_name_already_imported: false,
requires_import: false,
is_op_method: false,
@ -2439,4 +2443,81 @@ impl S {
"#,
)
}
#[test]
fn notable_traits_method_relevance() {
check_kinds(
r#"
#[doc(notable_trait)]
trait Write {
fn write(&self);
fn flush(&self);
}
struct Writer;
impl Write for Writer {
fn write(&self) {}
fn flush(&self) {}
}
fn main() {
Writer.$0
}
"#,
&[
CompletionItemKind::Method,
CompletionItemKind::SymbolKind(SymbolKind::Field),
CompletionItemKind::SymbolKind(SymbolKind::Function),
],
expect![[r#"
[
CompletionItem {
label: "flush()",
source_range: 193..193,
delete: 193..193,
insert: "flush()$0",
kind: Method,
lookup: "flush",
detail: "fn(&self)",
relevance: CompletionRelevance {
exact_name_match: false,
type_match: None,
is_local: false,
is_item_from_trait: false,
is_item_from_notable_trait: true,
is_name_already_imported: false,
requires_import: false,
is_op_method: false,
is_private_editable: false,
postfix_match: None,
is_definite: false,
},
},
CompletionItem {
label: "write()",
source_range: 193..193,
delete: 193..193,
insert: "write()$0",
kind: Method,
lookup: "write",
detail: "fn(&self)",
relevance: CompletionRelevance {
exact_name_match: false,
type_match: None,
is_local: false,
is_item_from_trait: false,
is_item_from_notable_trait: true,
is_name_already_imported: false,
requires_import: false,
is_op_method: false,
is_private_editable: false,
postfix_match: None,
is_definite: false,
},
},
]
"#]],
);
}
}

View File

@ -74,10 +74,13 @@ fn render(
);
let ret_type = func.ret_type(db);
let is_op_method = func
.as_assoc_item(ctx.db())
.and_then(|trait_| trait_.containing_trait_or_trait_impl(ctx.db()))
.map_or(false, |trait_| completion.is_ops_trait(trait_));
let assoc_item = func.as_assoc_item(db);
let trait_ = assoc_item.and_then(|trait_| trait_.containing_trait_or_trait_impl(db));
let is_op_method = trait_.map_or(false, |trait_| completion.is_ops_trait(trait_));
let is_item_from_notable_trait =
trait_.map_or(false, |trait_| completion.is_doc_notable_trait(trait_));
let (has_dot_receiver, has_call_parens, cap) = match func_kind {
FuncKind::Function(&PathCompletionCtx {
@ -105,6 +108,7 @@ fn render(
},
exact_name_match: compute_exact_name_match(completion, &call),
is_op_method,
is_item_from_notable_trait,
..ctx.completion_relevance()
});
@ -141,7 +145,7 @@ fn render(
item.add_import(import_to_add);
}
None => {
if let Some(actm) = func.as_assoc_item(db) {
if let Some(actm) = assoc_item {
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
item.trait_name(trt.name(db).to_smol_str());
}

View File

@ -84,73 +84,11 @@ impl RootDatabase {
)*}
}
purge_each_query![
// SourceDatabase
base_db::ParseQuery
base_db::CrateGraphQuery
// SourceDatabaseExt
base_db::FileTextQuery
base_db::FileSourceRootQuery
base_db::SourceRootQuery
base_db::SourceRootCratesQuery
// ExpandDatabase
hir::db::AstIdMapQuery
hir::db::DeclMacroExpanderQuery
hir::db::ExpandProcMacroQuery
hir::db::InternMacroCallQuery
hir::db::InternSyntaxContextQuery
hir::db::MacroArgQuery
hir::db::ParseMacroExpansionQuery
hir::db::RealSpanMapQuery
hir::db::ProcMacrosQuery
// DefDatabase
hir::db::FileItemTreeQuery
hir::db::CrateDefMapQueryQuery
hir::db::BlockDefMapQuery
hir::db::StructDataQuery
hir::db::StructDataWithDiagnosticsQuery
hir::db::UnionDataQuery
hir::db::UnionDataWithDiagnosticsQuery
hir::db::EnumDataQuery
hir::db::EnumDataWithDiagnosticsQuery
hir::db::ImplDataQuery
hir::db::ImplDataWithDiagnosticsQuery
hir::db::TraitDataQuery
hir::db::TraitDataWithDiagnosticsQuery
hir::db::TraitAliasDataQuery
hir::db::TypeAliasDataQuery
hir::db::FunctionDataQuery
hir::db::ConstDataQuery
hir::db::StaticDataQuery
hir::db::Macro2DataQuery
hir::db::MacroRulesDataQuery
hir::db::ProcMacroDataQuery
hir::db::BodyWithSourceMapQuery
hir::db::BodyQuery
hir::db::ExprScopesQuery
hir::db::GenericParamsQuery
hir::db::VariantsAttrsQuery
hir::db::FieldsAttrsQuery
hir::db::VariantsAttrsSourceMapQuery
hir::db::FieldsAttrsSourceMapQuery
hir::db::AttrsQuery
hir::db::CrateLangItemsQuery
hir::db::LangItemQuery
hir::db::ImportMapQuery
hir::db::FieldVisibilitiesQuery
hir::db::FunctionVisibilityQuery
hir::db::ConstVisibilityQuery
hir::db::CrateSupportsNoStdQuery
hir::db::BlockItemTreeQueryQuery
hir::db::ExternCrateDeclDataQuery
hir::db::LangAttrQuery
hir::db::InternAnonymousConstQuery
hir::db::InternExternCrateQuery
hir::db::InternInTypeConstQuery
hir::db::InternUseQuery
// SymbolsDatabase
crate::symbol_index::ModuleSymbolsQuery
crate::symbol_index::LibrarySymbolsQuery
crate::symbol_index::LocalRootsQuery
crate::symbol_index::LibraryRootsQuery
// HirDatabase
hir::db::InferQueryQuery
hir::db::MirBodyQuery
@ -194,14 +132,50 @@ impl RootDatabase {
hir::db::TraitSolveQueryQuery
hir::db::ProgramClausesForChalkEnvQuery
// SymbolsDatabase
crate::symbol_index::ModuleSymbolsQuery
crate::symbol_index::LibrarySymbolsQuery
crate::symbol_index::LocalRootsQuery
crate::symbol_index::LibraryRootsQuery
// LineIndexDatabase
crate::LineIndexQuery
// DefDatabase
hir::db::FileItemTreeQuery
hir::db::CrateDefMapQueryQuery
hir::db::BlockDefMapQuery
hir::db::StructDataQuery
hir::db::StructDataWithDiagnosticsQuery
hir::db::UnionDataQuery
hir::db::UnionDataWithDiagnosticsQuery
hir::db::EnumDataQuery
hir::db::EnumDataWithDiagnosticsQuery
hir::db::ImplDataQuery
hir::db::ImplDataWithDiagnosticsQuery
hir::db::TraitDataQuery
hir::db::TraitDataWithDiagnosticsQuery
hir::db::TraitAliasDataQuery
hir::db::TypeAliasDataQuery
hir::db::FunctionDataQuery
hir::db::ConstDataQuery
hir::db::StaticDataQuery
hir::db::Macro2DataQuery
hir::db::MacroRulesDataQuery
hir::db::ProcMacroDataQuery
hir::db::BodyWithSourceMapQuery
hir::db::BodyQuery
hir::db::ExprScopesQuery
hir::db::GenericParamsQuery
hir::db::VariantsAttrsQuery
hir::db::FieldsAttrsQuery
hir::db::VariantsAttrsSourceMapQuery
hir::db::FieldsAttrsSourceMapQuery
hir::db::AttrsQuery
hir::db::CrateLangItemsQuery
hir::db::LangItemQuery
hir::db::ImportMapQuery
hir::db::FieldVisibilitiesQuery
hir::db::FunctionVisibilityQuery
hir::db::ConstVisibilityQuery
hir::db::CrateSupportsNoStdQuery
hir::db::BlockItemTreeQueryQuery
hir::db::ExternCrateDeclDataQuery
hir::db::InternAnonymousConstQuery
hir::db::InternExternCrateQuery
hir::db::InternInTypeConstQuery
hir::db::InternUseQuery
// InternDatabase
hir::db::InternFunctionQuery
@ -219,6 +193,30 @@ impl RootDatabase {
hir::db::InternMacro2Query
hir::db::InternProcMacroQuery
hir::db::InternMacroRulesQuery
// ExpandDatabase
hir::db::AstIdMapQuery
hir::db::DeclMacroExpanderQuery
hir::db::ExpandProcMacroQuery
hir::db::InternMacroCallQuery
hir::db::InternSyntaxContextQuery
hir::db::MacroArgQuery
hir::db::ParseMacroExpansionQuery
hir::db::RealSpanMapQuery
hir::db::ProcMacrosQuery
// LineIndexDatabase
crate::LineIndexQuery
// SourceDatabase
base_db::ParseQuery
base_db::CrateGraphQuery
// SourceDatabaseExt
base_db::FileTextQuery
base_db::FileSourceRootQuery
base_db::SourceRootQuery
base_db::SourceRootCratesQuery
];
acc.sort_by_key(|it| std::cmp::Reverse(it.1));

View File

@ -681,11 +681,10 @@ fn path_import_candidate(
Some(qualifier) => match sema.resolve_path(&qualifier) {
None => {
if qualifier.first_qualifier().map_or(true, |it| sema.resolve_path(&it).is_none()) {
let mut qualifier = qualifier
.segments_of_this_path_only_rev()
let qualifier = qualifier
.segments()
.map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text())))
.collect::<Option<Vec<_>>>()?;
qualifier.reverse();
ImportCandidate::Path(PathImportCandidate { qualifier: Some(qualifier), name })
} else {
return None;

View File

@ -124,7 +124,7 @@ impl FileLoader for RootDatabase {
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
FileLoaderDelegate(self).resolve_path(path)
}
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> {
FileLoaderDelegate(self).relevant_crates(file_id)
}
}
@ -145,7 +145,7 @@ impl RootDatabase {
db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
db.set_expand_proc_attr_macros_with_durability(false, Durability::HIGH);
db.update_parse_query_lru_capacity(lru_capacity);
db.update_base_query_lru_capacities(lru_capacity);
db.setup_syntax_context_root();
db
}
@ -154,11 +154,12 @@ impl RootDatabase {
self.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
}
pub fn update_parse_query_lru_capacity(&mut self, lru_capacity: Option<usize>) {
pub fn update_base_query_lru_capacities(&mut self, lru_capacity: Option<usize>) {
let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_PARSE_LRU_CAP);
base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
// macro expansions are usually rather small, so we can afford to keep more of them alive
hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(4 * lru_capacity);
hir::db::BorrowckQuery.in_db_mut(self).set_lru_capacity(base_db::DEFAULT_BORROWCK_LRU_CAP);
}
pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap<Box<str>, usize>) {
@ -176,6 +177,12 @@ impl RootDatabase {
.copied()
.unwrap_or(4 * base_db::DEFAULT_PARSE_LRU_CAP),
);
hir_db::BorrowckQuery.in_db_mut(self).set_lru_capacity(
lru_capacities
.get(stringify!(BorrowckQuery))
.copied()
.unwrap_or(base_db::DEFAULT_BORROWCK_LRU_CAP),
);
macro_rules! update_lru_capacity_per_query {
($( $module:ident :: $query:ident )*) => {$(

View File

@ -3,6 +3,7 @@
use crate::helpers::mod_path_to_ast;
use either::Either;
use hir::{AsAssocItem, HirDisplay, ModuleDef, SemanticsScope};
use itertools::Itertools;
use rustc_hash::FxHashMap;
use syntax::{
ast::{self, make, AstNode},
@ -227,11 +228,15 @@ struct Ctx<'a> {
same_self_type: bool,
}
fn postorder(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
item.preorder().filter_map(|event| match event {
syntax::WalkEvent::Enter(_) => None,
syntax::WalkEvent::Leave(node) => Some(node),
})
fn preorder_rev(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
let x = item
.preorder()
.filter_map(|event| match event {
syntax::WalkEvent::Enter(node) => Some(node),
syntax::WalkEvent::Leave(_) => None,
})
.collect_vec();
x.into_iter().rev()
}
impl Ctx<'_> {
@ -239,12 +244,12 @@ impl Ctx<'_> {
// `transform_path` may update a node's parent and that would break the
// tree traversal. Thus all paths in the tree are collected into a vec
// so that such operation is safe.
let paths = postorder(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
let paths = preorder_rev(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
for path in paths {
self.transform_path(path);
}
postorder(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
preorder_rev(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
}
@ -263,7 +268,7 @@ impl Ctx<'_> {
// `transform_path` may update a node's parent and that would break the
// tree traversal. Thus all paths in the tree are collected into a vec
// so that such operation is safe.
let paths = postorder(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
let paths = preorder_rev(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
for path in paths {
self.transform_path(path);
}

View File

@ -356,7 +356,7 @@ impl Definition {
if let Some(Visibility::Public) = vis {
return SearchScope::reverse_dependencies(db, module.krate());
}
if let Some(Visibility::Module(module)) = vis {
if let Some(Visibility::Module(module, _)) = vis {
return SearchScope::module_and_children(db, module.into());
}

View File

@ -13,6 +13,7 @@ pub(crate) fn unresolved_assoc_item(
"no such associated item",
d.expr_or_pat.clone().map(Into::into),
)
.experimental()
}
#[cfg(test)]

View File

@ -481,7 +481,7 @@ struct Foo {}
"#,
expect![[r#"
Clone
impl < >core::clone::Clone for Foo< >where {
impl < >$crate::clone::Clone for Foo< >where {
fn clone(&self) -> Self {
match self {
Foo{}
@ -507,7 +507,7 @@ struct Foo {}
"#,
expect![[r#"
Copy
impl < >core::marker::Copy for Foo< >where{}"#]],
impl < >$crate::marker::Copy for Foo< >where{}"#]],
);
}
@ -522,7 +522,7 @@ struct Foo {}
"#,
expect![[r#"
Copy
impl < >core::marker::Copy for Foo< >where{}"#]],
impl < >$crate::marker::Copy for Foo< >where{}"#]],
);
check(
r#"
@ -533,7 +533,7 @@ struct Foo {}
"#,
expect![[r#"
Clone
impl < >core::clone::Clone for Foo< >where {
impl < >$crate::clone::Clone for Foo< >where {
fn clone(&self) -> Self {
match self {
Foo{}

View File

@ -171,7 +171,7 @@ impl AnalysisHost {
}
pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
self.db.update_parse_query_lru_capacity(lru_capacity);
self.db.update_base_query_lru_capacities(lru_capacity);
}
pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap<Box<str>, usize>) {

View File

@ -322,7 +322,7 @@ fn load_crate_graph(
break;
}
}
vfs::loader::Message::Loaded { files } => {
vfs::loader::Message::Loaded { files } | vfs::loader::Message::Changed { files } => {
for (path, contents) in files {
vfs.set_file_contents(path.into(), contents);
}
@ -331,9 +331,8 @@ fn load_crate_graph(
}
let changes = vfs.take_changes();
for file in changes {
if file.exists() {
let contents = vfs.file_contents(file.file_id);
if let Ok(text) = std::str::from_utf8(contents) {
if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change {
if let Ok(text) = std::str::from_utf8(&v) {
analysis_change.change_file(file.file_id, Some(text.into()))
}
}

View File

@ -13,8 +13,7 @@ doctest = false
[dependencies]
drop_bomb = "0.1.5"
rustc-dependencies.workspace = true
ra-ap-rustc_lexer.workspace = true
limit.workspace = true
[dev-dependencies]
@ -24,7 +23,7 @@ stdx.workspace = true
sourcegen.workspace = true
[features]
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
in-rust-tree = []
[lints]
workspace = true
workspace = true

View File

@ -371,7 +371,15 @@ fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLik
if p.at(op) {
m = p.start();
p.bump(op);
if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
// test closure_range_method_call
// fn foo() {
// || .. .method();
// || .. .field;
// }
let has_access_after = p.at(T![.]) && p.nth_at(1, SyntaxKind::IDENT);
let struct_forbidden = r.forbid_structs && p.at(T!['{']);
if p.at_ts(EXPR_FIRST) && !has_access_after && !struct_forbidden {
expr_bp(p, None, r, 2);
}
let cm = m.complete(p, RANGE_EXPR);

View File

@ -8,8 +8,6 @@
//! Note that these tokens, unlike the tokens we feed into the parser, do
//! include info about comments and whitespace.
use rustc_dependencies::lexer as rustc_lexer;
use std::ops;
use rustc_lexer::unescape::{EscapeError, Mode};

View File

@ -21,6 +21,11 @@
#![allow(rustdoc::private_intra_doc_links)]
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_lexer as rustc_lexer;
#[cfg(feature = "in-rust-tree")]
extern crate rustc_lexer;
mod lexed_str;
mod token_set;
mod syntax_kind;

View File

@ -0,0 +1,49 @@
SOURCE_FILE
FN
FN_KW "fn"
WHITESPACE " "
NAME
IDENT "foo"
PARAM_LIST
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
BLOCK_EXPR
STMT_LIST
L_CURLY "{"
WHITESPACE "\n "
EXPR_STMT
METHOD_CALL_EXPR
CLOSURE_EXPR
PARAM_LIST
PIPE "|"
PIPE "|"
WHITESPACE " "
RANGE_EXPR
DOT2 ".."
WHITESPACE " "
DOT "."
NAME_REF
IDENT "method"
ARG_LIST
L_PAREN "("
R_PAREN ")"
SEMICOLON ";"
WHITESPACE "\n "
EXPR_STMT
FIELD_EXPR
CLOSURE_EXPR
PARAM_LIST
PIPE "|"
PIPE "|"
WHITESPACE " "
RANGE_EXPR
DOT2 ".."
WHITESPACE " "
DOT "."
NAME_REF
IDENT "field"
SEMICOLON ";"
WHITESPACE "\n"
R_CURLY "}"
WHITESPACE "\n"

View File

@ -0,0 +1,4 @@
fn foo() {
|| .. .method();
|| .. .field;
}

View File

@ -14,8 +14,10 @@ mod version;
use indexmap::IndexSet;
use paths::AbsPathBuf;
use span::Span;
use std::{fmt, io, sync::Mutex};
use triomphe::Arc;
use std::{
fmt, io,
sync::{Arc, Mutex},
};
use serde::{Deserialize, Serialize};
@ -81,9 +83,11 @@ impl PartialEq for ProcMacro {
}
}
#[derive(Clone, Debug)]
pub struct ServerError {
pub message: String,
pub io: Option<io::Error>,
// io::Error isn't Clone for some reason
pub io: Option<Arc<io::Error>>,
}
impl fmt::Display for ServerError {

View File

@ -1,8 +1,9 @@
//! Handle process life-time and message passing for proc-macro client
use std::{
io::{self, BufRead, BufReader, Write},
io::{self, BufRead, BufReader, Read, Write},
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
sync::Arc,
};
use paths::{AbsPath, AbsPathBuf};
@ -15,9 +16,11 @@ use crate::{
#[derive(Debug)]
pub(crate) struct ProcMacroProcessSrv {
_process: Process,
process: Process,
stdin: ChildStdin,
stdout: BufReader<ChildStdout>,
/// Populated when the server exits.
server_exited: Option<ServerError>,
version: u32,
mode: SpanMode,
}
@ -29,9 +32,10 @@ impl ProcMacroProcessSrv {
let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
io::Result::Ok(ProcMacroProcessSrv {
_process: process,
process,
stdin,
stdout,
server_exited: None,
version: 0,
mode: SpanMode::Id,
})
@ -105,8 +109,35 @@ impl ProcMacroProcessSrv {
}
pub(crate) fn send_task(&mut self, req: Request) -> Result<Response, ServerError> {
if let Some(server_error) = &self.server_exited {
return Err(server_error.clone());
}
let mut buf = String::new();
send_request(&mut self.stdin, &mut self.stdout, req, &mut buf)
send_request(&mut self.stdin, &mut self.stdout, req, &mut buf).map_err(|e| {
if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) {
match self.process.child.try_wait() {
Ok(None) => e,
Ok(Some(status)) => {
let mut msg = String::new();
if !status.success() {
if let Some(stderr) = self.process.child.stderr.as_mut() {
_ = stderr.read_to_string(&mut msg);
}
}
let server_error = ServerError {
message: format!("server exited with {status}: {msg}"),
io: None,
};
self.server_exited = Some(server_error.clone());
server_error
}
Err(_) => e,
}
} else {
e
}
})
}
}
@ -131,12 +162,19 @@ impl Process {
}
fn mk_child(path: &AbsPath, null_stderr: bool) -> io::Result<Child> {
Command::new(path.as_os_str())
.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
let mut cmd = Command::new(path.as_os_str());
cmd.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() })
.spawn()
.stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() });
if cfg!(windows) {
let mut path_var = std::ffi::OsString::new();
path_var.push(path.parent().unwrap().parent().unwrap().as_os_str());
path_var.push("\\bin;");
path_var.push(std::env::var_os("PATH").unwrap_or_default());
cmd.env("PATH", path_var);
}
cmd.spawn()
}
fn send_request(
@ -145,9 +183,13 @@ fn send_request(
req: Request,
buf: &mut String,
) -> Result<Response, ServerError> {
req.write(&mut writer)
.map_err(|err| ServerError { message: "failed to write request".into(), io: Some(err) })?;
let res = Response::read(&mut reader, buf)
.map_err(|err| ServerError { message: "failed to read response".into(), io: Some(err) })?;
req.write(&mut writer).map_err(|err| ServerError {
message: "failed to write request".into(),
io: Some(Arc::new(err)),
})?;
let res = Response::read(&mut reader, buf).map_err(|err| ServerError {
message: "failed to read response".into(),
io: Some(Arc::new(err)),
})?;
res.ok_or_else(|| ServerError { message: "server exited".into(), io: None })
}

View File

@ -24,7 +24,8 @@ fn main() -> std::io::Result<()> {
#[cfg(not(any(feature = "sysroot-abi", rust_analyzer)))]
fn run() -> io::Result<()> {
panic!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled");
eprintln!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled");
std::process::exit(70);
}
#[cfg(any(feature = "sysroot-abi", rust_analyzer))]

View File

@ -37,7 +37,7 @@ expect-test = "1.4.0"
proc-macro-test.path = "./proc-macro-test"
[features]
sysroot-abi = ["proc-macro-test/sysroot-abi"]
sysroot-abi = []
in-rust-tree = ["mbe/in-rust-tree", "sysroot-abi"]
[lints]

View File

@ -14,6 +14,3 @@ cargo_metadata = "0.18.1"
# local deps
toolchain.workspace = true
[features]
sysroot-abi = []

View File

@ -17,11 +17,24 @@ use cargo_metadata::Message;
fn main() {
println!("cargo:rerun-if-changed=imp");
println!("cargo:rerun-if-env-changed=PROC_MACRO_TEST_TOOLCHAIN");
let has_features = env::var_os("RUSTC_BOOTSTRAP").is_some()
|| String::from_utf8(
Command::new(toolchain::cargo()).arg("--version").output().unwrap().stdout,
)
.unwrap()
.contains("nightly");
let out_dir = env::var_os("OUT_DIR").unwrap();
let out_dir = Path::new(&out_dir);
if !has_features {
println!("proc-macro-test testing only works on nightly toolchains");
let info_path = out_dir.join("proc_macro_test_location.txt");
fs::File::create(info_path).unwrap();
return;
}
let name = "proc-macro-test-impl";
let version = "0.0.0";
@ -53,15 +66,7 @@ fn main() {
let target_dir = out_dir.join("target");
let mut cmd = if let Ok(toolchain) = std::env::var("PROC_MACRO_TEST_TOOLCHAIN") {
// leverage rustup to find user-specific toolchain
let mut cmd = Command::new("cargo");
cmd.arg(format!("+{toolchain}"));
cmd
} else {
Command::new(toolchain::cargo())
};
let mut cmd = Command::new(toolchain::cargo());
cmd.current_dir(&staging_dir)
.args(["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
// Explicit override the target directory to avoid using the same one which the parent
@ -70,9 +75,6 @@ fn main() {
// instance to use the same target directory.
.arg("--target-dir")
.arg(&target_dir);
if cfg!(feature = "sysroot-abi") {
cmd.args(["--features", "sysroot-abi"]);
}
if let Ok(target) = std::env::var("TARGET") {
cmd.args(["--target", &target]);

View File

@ -13,7 +13,4 @@ proc-macro = true
# this crate should not have any dependencies, since it uses its own workspace,
# and its own `Cargo.lock`
[features]
sysroot-abi = []
[workspace]

View File

@ -1,8 +1,5 @@
//! Exports a few trivial procedural macros for testing.
#![allow(unexpected_cfgs)]
#![cfg(feature = "sysroot-abi")]
#![cfg(any(feature = "sysroot-abi", rust_analyzer))]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![feature(proc_macro_span, proc_macro_def_site)]

View File

@ -11,11 +11,13 @@
//! rustc rather than `unstable`. (Although in general ABI compatibility is still an issue)…
#![cfg(any(feature = "sysroot-abi", rust_analyzer))]
#![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span, rustc_private)]
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(unreachable_pub, internal_features)]
extern crate proc_macro;
#[cfg(feature = "in-rust-tree")]
extern crate rustc_driver as _;
mod dylib;

View File

@ -1398,7 +1398,7 @@ fn sysroot_to_crate_graph(
let public_deps = SysrootPublicDeps {
deps: sysroot
.public_deps()
.map(|(name, idx, prelude)| (name, sysroot_crates[&idx], prelude))
.filter_map(|(name, idx, prelude)| Some((name, *sysroot_crates.get(&idx)?, prelude)))
.collect::<Vec<_>>(),
};

View File

@ -49,7 +49,6 @@ flycheck.workspace = true
hir-def.workspace = true
hir-ty.workspace = true
hir.workspace = true
rustc-dependencies.workspace = true
ide-db.workspace = true
# This should only be used in CLI
ide-ssr.workspace = true
@ -89,11 +88,10 @@ in-rust-tree = [
"ide/in-rust-tree",
"syntax/in-rust-tree",
"parser/in-rust-tree",
"rustc-dependencies/in-rust-tree",
"hir/in-rust-tree",
"hir-def/in-rust-tree",
"hir-ty/in-rust-tree",
]
[lints]
workspace = true
workspace = true

View File

@ -3,7 +3,7 @@
//!
//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
use std::time::Instant;
use std::{collections::hash_map::Entry, time::Instant};
use crossbeam_channel::{unbounded, Receiver, Sender};
use flycheck::FlycheckHandle;
@ -21,7 +21,7 @@ use proc_macro_api::ProcMacroServer;
use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
use rustc_hash::{FxHashMap, FxHashSet};
use triomphe::Arc;
use vfs::{AnchoredPathBuf, Vfs};
use vfs::{AnchoredPathBuf, ChangedFile, Vfs};
use crate::{
config::{Config, ConfigError},
@ -217,8 +217,8 @@ impl GlobalState {
pub(crate) fn process_changes(&mut self) -> bool {
let _p = profile::span("GlobalState::process_changes");
let mut file_changes = FxHashMap::default();
let (change, changed_files, workspace_structure_change) = {
let mut file_changes = FxHashMap::<_, (bool, ChangedFile)>::default();
let (change, modified_rust_files, workspace_structure_change) = {
let mut change = Change::new();
let mut guard = self.vfs.write();
let changed_files = guard.0.take_changes();
@ -233,64 +233,63 @@ impl GlobalState {
// id that is followed by a delete we actually skip observing the file text from the
// earlier event, to avoid problems later on.
for changed_file in changed_files {
use vfs::ChangeKind::*;
file_changes
.entry(changed_file.file_id)
.and_modify(|(change, just_created)| {
// None -> Delete => keep
// Create -> Delete => collapse
//
match (change, just_created, changed_file.change_kind) {
use vfs::Change::*;
match file_changes.entry(changed_file.file_id) {
Entry::Occupied(mut o) => {
let (just_created, change) = o.get_mut();
match (&mut change.change, just_created, changed_file.change) {
// latter `Delete` wins
(change, _, Delete) => *change = Delete,
// merge `Create` with `Create` or `Modify`
(Create, _, Create | Modify) => {}
(Create(prev), _, Create(new) | Modify(new)) => *prev = new,
// collapse identical `Modify`es
(Modify, _, Modify) => {}
(Modify(prev), _, Modify(new)) => *prev = new,
// equivalent to `Modify`
(change @ Delete, just_created, Create) => {
*change = Modify;
(change @ Delete, just_created, Create(new)) => {
*change = Modify(new);
*just_created = true;
}
// shouldn't occur, but collapse into `Create`
(change @ Delete, just_created, Modify) => {
*change = Create;
(change @ Delete, just_created, Modify(new)) => {
*change = Create(new);
*just_created = true;
}
// shouldn't occur, but collapse into `Modify`
(Modify, _, Create) => {}
// shouldn't occur, but keep the Create
(prev @ Modify(_), _, new @ Create(_)) => *prev = new,
}
})
.or_insert((
changed_file.change_kind,
matches!(changed_file.change_kind, Create),
));
}
Entry::Vacant(v) => {
_ = v.insert((matches!(&changed_file.change, Create(_)), changed_file))
}
}
}
let changed_files: Vec<_> = file_changes
.into_iter()
.filter(|(_, (change_kind, just_created))| {
!matches!((change_kind, just_created), (vfs::ChangeKind::Delete, true))
.filter(|(_, (just_created, change))| {
!(*just_created && matches!(change.change, vfs::Change::Delete))
})
.map(|(file_id, (change_kind, _))| vfs::ChangedFile { file_id, change_kind })
.map(|(file_id, (_, change))| vfs::ChangedFile { file_id, ..change })
.collect();
let mut workspace_structure_change = None;
// A file was added or deleted
let mut has_structure_changes = false;
let mut bytes = vec![];
for file in &changed_files {
let mut modified_rust_files = vec![];
for file in changed_files {
let vfs_path = &vfs.file_path(file.file_id);
if let Some(path) = vfs_path.as_path() {
let path = path.to_path_buf();
if reload::should_refresh_for_change(&path, file.change_kind) {
if reload::should_refresh_for_change(&path, file.kind()) {
workspace_structure_change = Some((path.clone(), false));
}
if file.is_created_or_deleted() {
has_structure_changes = true;
workspace_structure_change =
Some((path, self.crate_graph_file_dependencies.contains(vfs_path)));
} else if path.extension() == Some("rs".as_ref()) {
modified_rust_files.push(file.file_id);
}
}
@ -299,10 +298,8 @@ impl GlobalState {
self.diagnostics.clear_native_for(file.file_id);
}
let text = if file.exists() {
let bytes = vfs.file_contents(file.file_id).to_vec();
String::from_utf8(bytes).ok().and_then(|text| {
let text = if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change {
String::from_utf8(v).ok().and_then(|text| {
// FIXME: Consider doing normalization in the `vfs` instead? That allows
// getting rid of some locking
let (text, line_endings) = LineEndings::normalize(text);
@ -327,11 +324,10 @@ impl GlobalState {
let roots = self.source_root_config.partition(vfs);
change.set_roots(roots);
}
(change, changed_files, workspace_structure_change)
(change, modified_rust_files, workspace_structure_change)
};
self.analysis_host.apply_change(change);
{
let raw_database = self.analysis_host.raw_database();
// FIXME: ideally we should only trigger a workspace fetch for non-library changes
@ -343,13 +339,12 @@ impl GlobalState {
force_crate_graph_reload,
);
}
self.proc_macro_changed =
changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
let crates = raw_database.relevant_crates(file.file_id);
let crate_graph = raw_database.crate_graph();
self.proc_macro_changed = modified_rust_files.into_iter().any(|file_id| {
let crates = raw_database.relevant_crates(file_id);
let crate_graph = raw_database.crate_graph();
crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
});
crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
});
}
true
@ -494,10 +489,6 @@ impl GlobalStateSnapshot {
})
}
pub(crate) fn vfs_memory_usage(&self) -> usize {
self.vfs_read().memory_usage()
}
pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
self.vfs.read().0.exists(file_id)
}

View File

@ -59,7 +59,13 @@ pub(crate) fn handle_did_open_text_document(
if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
let already_exists = state
.mem_docs
.insert(path.clone(), DocumentData::new(params.text_document.version))
.insert(
path.clone(),
DocumentData::new(
params.text_document.version,
params.text_document.text.clone().into_bytes(),
),
)
.is_err();
if already_exists {
tracing::error!("duplicate DidOpenTextDocument: {}", path);
@ -76,11 +82,12 @@ pub(crate) fn handle_did_change_text_document(
let _p = profile::span("handle_did_change_text_document");
if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
match state.mem_docs.get_mut(&path) {
let data = match state.mem_docs.get_mut(&path) {
Some(doc) => {
// The version passed in DidChangeTextDocument is the version after all edits are applied
// so we should apply it before the vfs is notified.
doc.version = params.text_document.version;
&mut doc.data
}
None => {
tracing::error!("unexpected DidChangeTextDocument: {}", path);
@ -88,16 +95,16 @@ pub(crate) fn handle_did_change_text_document(
}
};
let text = apply_document_changes(
let new_contents = apply_document_changes(
state.config.position_encoding(),
|| {
let vfs = &state.vfs.read().0;
let file_id = vfs.file_id(&path).unwrap();
std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into()
},
std::str::from_utf8(data).unwrap(),
params.content_changes,
);
state.vfs.write().0.set_file_contents(path, Some(text.into_bytes()));
)
.into_bytes();
if *data != new_contents {
*data = new_contents.clone();
state.vfs.write().0.set_file_contents(path, Some(new_contents));
}
}
Ok(())
}

View File

@ -103,7 +103,6 @@ pub(crate) fn handle_analyzer_status(
.collect::<Vec<&AbsPath>>()
);
}
format_to!(buf, "\nVfs memory usage: {}\n", profile::Bytes::new(snap.vfs_memory_usage() as _));
buf.push_str("\nAnalysis:\n");
buf.push_str(
&snap

View File

@ -168,7 +168,7 @@ impl GlobalState {
pub(crate) fn apply_document_changes(
encoding: PositionEncoding,
file_contents: impl FnOnce() -> String,
file_contents: &str,
mut content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>,
) -> String {
// If at least one of the changes is a full document change, use the last
@ -179,7 +179,7 @@ pub(crate) fn apply_document_changes(
let text = mem::take(&mut content_changes[idx].text);
(text, &content_changes[idx + 1..])
}
None => (file_contents(), &content_changes[..]),
None => (file_contents.to_owned(), &content_changes[..]),
};
if content_changes.is_empty() {
return text;
@ -276,11 +276,11 @@ mod tests {
}
let encoding = PositionEncoding::Wide(WideEncoding::Utf16);
let text = apply_document_changes(encoding, || String::new(), vec![]);
let text = apply_document_changes(encoding, "", vec![]);
assert_eq!(text, "");
let text = apply_document_changes(
encoding,
|| text,
&text,
vec![TextDocumentContentChangeEvent {
range: None,
range_length: None,
@ -288,49 +288,46 @@ mod tests {
}],
);
assert_eq!(text, "the");
let text = apply_document_changes(encoding, || text, c![0, 3; 0, 3 => " quick"]);
let text = apply_document_changes(encoding, &text, c![0, 3; 0, 3 => " quick"]);
assert_eq!(text, "the quick");
let text =
apply_document_changes(encoding, || text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]);
apply_document_changes(encoding, &text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]);
assert_eq!(text, "quick foxes");
let text = apply_document_changes(encoding, || text, c![0, 11; 0, 11 => "\ndream"]);
let text = apply_document_changes(encoding, &text, c![0, 11; 0, 11 => "\ndream"]);
assert_eq!(text, "quick foxes\ndream");
let text = apply_document_changes(encoding, || text, c![1, 0; 1, 0 => "have "]);
let text = apply_document_changes(encoding, &text, c![1, 0; 1, 0 => "have "]);
assert_eq!(text, "quick foxes\nhave dream");
let text = apply_document_changes(
encoding,
|| text,
&text,
c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"],
);
assert_eq!(text, "the quick foxes\nhave quiet dreams\n");
let text = apply_document_changes(
encoding,
|| text,
c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"],
);
let text =
apply_document_changes(encoding, &text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]);
assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n");
let text = apply_document_changes(
encoding,
|| text,
&text,
c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"],
);
assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n");
let text =
apply_document_changes(encoding, || text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]);
apply_document_changes(encoding, &text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]);
assert_eq!(text, "the quick \nthey have quiet dreams\n");
let text = String::from("❤️");
let text = apply_document_changes(encoding, || text, c![0, 0; 0, 0 => "a"]);
let text = apply_document_changes(encoding, &text, c![0, 0; 0, 0 => "a"]);
assert_eq!(text, "a❤");
let text = String::from("a\nb");
let text =
apply_document_changes(encoding, || text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]);
apply_document_changes(encoding, &text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]);
assert_eq!(text, "adcb");
let text = String::from("a\nb");
let text =
apply_document_changes(encoding, || text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]);
apply_document_changes(encoding, &text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]);
assert_eq!(text, "ațc\ncb");
}

View File

@ -571,13 +571,18 @@ impl GlobalState {
}
fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
let is_changed = matches!(message, vfs::loader::Message::Changed { .. });
match message {
vfs::loader::Message::Loaded { files } => {
vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
let vfs = &mut self.vfs.write().0;
for (path, contents) in files {
let path = VfsPath::from(path);
// if the file is in mem docs, it's managed by the client via notifications
// so only set it if its not in there
if !self.mem_docs.contains(&path) {
vfs.set_file_contents(path, contents);
if is_changed || vfs.file_id(&path).is_none() {
vfs.set_file_contents(path, contents);
}
}
}
}

View File

@ -62,10 +62,11 @@ impl MemDocs {
#[derive(Debug, Clone)]
pub(crate) struct DocumentData {
pub(crate) version: i32,
pub(crate) data: Vec<u8>,
}
impl DocumentData {
pub(crate) fn new(version: i32) -> Self {
DocumentData { version }
pub(crate) fn new(version: i32, data: Vec<u8>) -> Self {
DocumentData { version, data }
}
}

View File

@ -503,10 +503,9 @@ impl GlobalState {
match vfs.file_id(&vfs_path) {
Some(file_id) => Some(file_id),
None => {
if !self.mem_docs.contains(&vfs_path) {
let contents = loader.handle.load_sync(path);
vfs.set_file_contents(vfs_path.clone(), contents);
}
// FIXME: Consider not loading this here?
let contents = loader.handle.load_sync(path);
vfs.set_file_contents(vfs_path.clone(), contents);
vfs.file_id(&vfs_path)
}
}

View File

@ -1,23 +0,0 @@
[package]
name = "rustc-dependencies"
version = "0.0.0"
description = "TBD"
rust-version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ra-ap-rustc_lexer = { version = "0.21.0" }
ra-ap-rustc_parse_format = { version = "0.21.0", default-features = false }
ra-ap-rustc_index = { version = "0.21.0", default-features = false }
ra-ap-rustc_abi = { version = "0.21.0", default-features = false }
[features]
in-rust-tree = []
[lints]
workspace = true

View File

@ -1,48 +0,0 @@
//! A wrapper around rustc internal crates, which enables switching between compiler provided
//! ones and stable ones published in crates.io
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#[cfg(feature = "in-rust-tree")]
extern crate rustc_lexer;
pub mod lexer {
#[cfg(not(feature = "in-rust-tree"))]
pub use ::ra_ap_rustc_lexer::*;
#[cfg(feature = "in-rust-tree")]
pub use ::rustc_lexer::*;
}
#[cfg(feature = "in-rust-tree")]
extern crate rustc_parse_format;
pub mod parse_format {
#[cfg(not(feature = "in-rust-tree"))]
pub use ::ra_ap_rustc_parse_format::*;
#[cfg(feature = "in-rust-tree")]
pub use ::rustc_parse_format::*;
}
#[cfg(feature = "in-rust-tree")]
extern crate rustc_abi;
pub mod abi {
#[cfg(not(feature = "in-rust-tree"))]
pub use ::ra_ap_rustc_abi::*;
#[cfg(feature = "in-rust-tree")]
pub use ::rustc_abi::*;
}
#[cfg(feature = "in-rust-tree")]
extern crate rustc_index;
pub mod index {
#[cfg(not(feature = "in-rust-tree"))]
pub use ::ra_ap_rustc_index::*;
#[cfg(feature = "in-rust-tree")]
pub use ::rustc_index::*;
}

View File

@ -23,7 +23,7 @@ indexmap.workspace = true
smol_str.workspace = true
triomphe.workspace = true
rustc-dependencies.workspace = true
ra-ap-rustc_lexer.workspace = true
parser.workspace = true
profile.workspace = true
@ -41,7 +41,7 @@ test-utils.workspace = true
sourcegen.workspace = true
[features]
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
in-rust-tree = []
[lints]
workspace = true
workspace = true

View File

@ -285,14 +285,16 @@ impl ast::Path {
self.first_qualifier_or_self().segment()
}
// FIXME: Check usages of Self::segments, they might be wrong because of the logic of the bloew function
pub fn segments_of_this_path_only_rev(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
self.qualifiers_and_self().filter_map(|it| it.segment())
}
pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
successors(self.first_segment(), |p| {
p.parent_path().parent_path().and_then(|p| p.segment())
let path_range = self.syntax().text_range();
successors(self.first_segment(), move |p| {
p.parent_path().parent_path().and_then(|p| {
if path_range.contains_range(p.syntax().text_range()) {
p.segment()
} else {
None
}
})
})
}
@ -300,10 +302,6 @@ impl ast::Path {
successors(self.qualifier(), |p| p.qualifier())
}
pub fn qualifiers_and_self(&self) -> impl Iterator<Item = ast::Path> + Clone {
successors(Some(self.clone()), |p| p.qualifier())
}
pub fn top_path(&self) -> ast::Path {
let mut this = self.clone();
while let Some(path) = this.parent_path() {

View File

@ -2,8 +2,6 @@
use std::borrow::Cow;
use rustc_dependencies::lexer as rustc_lexer;
use rustc_lexer::unescape::{
unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode,
};

View File

@ -22,6 +22,11 @@
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#![warn(rust_2018_idioms, unused_lifetimes)]
#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_lexer as rustc_lexer;
#[cfg(feature = "in-rust-tree")]
extern crate rustc_lexer;
#[allow(unused)]
macro_rules! eprintln {
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };

View File

@ -5,7 +5,7 @@
mod block;
use rowan::Direction;
use rustc_dependencies::lexer::unescape::{self, unescape_literal, Mode};
use rustc_lexer::unescape::{self, unescape_literal, Mode};
use crate::{
algo,

View File

@ -25,6 +25,7 @@
//! derive:
//! discriminant:
//! drop:
//! env: option
//! eq: sized
//! error: fmt
//! fmt: result, transmute, coerce_unsized
@ -1450,6 +1451,15 @@ mod macros {
#[macro_export]
macro_rules! concat {}
// endregion:concat
// region:env
#[rustc_builtin_macro]
#[macro_export]
macro_rules! env {}
#[rustc_builtin_macro]
#[macro_export]
macro_rules! option_env {}
// endregion:env
}
// region:non_zero

View File

@ -160,7 +160,7 @@ impl NotifyActor {
Some((path, contents))
})
.collect();
self.send(loader::Message::Loaded { files });
self.send(loader::Message::Changed { files });
}
}
}

Some files were not shown because too many files have changed in this diff Show More